getData() {
- return data;
+ return this.data;
}
}
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/AuthenticateWithPasswordRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/AuthenticateWithPasswordRequest.java
index f707e3ba2c4..65d9e4b1f28 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/AuthenticateWithPasswordRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/AuthenticateWithPasswordRequest.java
@@ -1,17 +1,18 @@
package io.openems.common.jsonrpc.request;
-import java.util.UUID;
+import java.util.Optional;
import com.google.gson.JsonObject;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
-import io.openems.common.jsonrpc.base.GenericJsonrpcRequest;
import io.openems.common.jsonrpc.base.JsonrpcRequest;
import io.openems.common.utils.JsonUtils;
+import io.openems.common.utils.JsonUtils.JsonObjectBuilder;
/**
* Represents a JSON-RPC Request to authenticate with a Password.
*
+ *
* This is used by UI to login with password-only at the Edge.
*
*
@@ -20,6 +21,7 @@
* "id": "UUID",
* "method": "authenticateWithPassword",
* "params": {
+ * "username"?: string,
* "password": string
* }
* }
@@ -27,37 +29,63 @@
*/
public class AuthenticateWithPasswordRequest extends JsonrpcRequest {
- public final static String METHOD = "authenticateWithPassword";
+ public static final String METHOD = "authenticateWithPassword";
+ /**
+ * Create {@link AuthenticateWithPasswordRequest} from a template
+ * {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link AuthenticateWithPasswordRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static AuthenticateWithPasswordRequest from(JsonrpcRequest r) throws OpenemsNamedException {
JsonObject p = r.getParams();
+ Optional username = JsonUtils.getAsOptionalString(p, "username");
String password = JsonUtils.getAsString(p, "password");
- return new AuthenticateWithPasswordRequest(r.getId(), password);
- }
-
- public static AuthenticateWithPasswordRequest from(JsonObject j) throws OpenemsNamedException {
- return from(GenericJsonrpcRequest.from(j));
+ return new AuthenticateWithPasswordRequest(r, username, password);
}
+ private final Optional username;
private final String password;
- public AuthenticateWithPasswordRequest(UUID id, String password) {
- super(id, METHOD);
+ private AuthenticateWithPasswordRequest(JsonrpcRequest request, Optional username, String password) {
+ super(request, METHOD);
+ this.username = username;
+ this.password = password;
+ }
+
+ public AuthenticateWithPasswordRequest(Optional username, String password) {
+ super(METHOD);
+ this.username = username;
this.password = password;
}
- public AuthenticateWithPasswordRequest(String password) {
- this(UUID.randomUUID(), password);
+ /**
+ * Gets the Username if given.
+ *
+ * @return Username
+ */
+ public Optional getUsername() {
+ return this.username;
}
+ /**
+ * Gets the Password.
+ *
+ * @return Password
+ */
public String getPassword() {
- return password;
+ return this.password;
}
@Override
public JsonObject getParams() {
- return JsonUtils.buildJsonObject() //
- .addProperty("password", this.password) //
- .build();
+ JsonObjectBuilder result = JsonUtils.buildJsonObject() //
+ .addProperty("password", this.password); //
+ if (this.username.isPresent()) {
+ result.addProperty("username", this.username.get()); //
+ }
+ return result.build();
}
}
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/AuthenticatedRpcRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/AuthenticatedRpcRequest.java
index ce98cc312a5..08f8d6e6482 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/AuthenticatedRpcRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/AuthenticatedRpcRequest.java
@@ -1,7 +1,5 @@
package io.openems.common.jsonrpc.request;
-import java.util.UUID;
-
import com.google.gson.JsonObject;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
@@ -31,34 +29,54 @@
*/
public class AuthenticatedRpcRequest extends JsonrpcRequest {
- public final static String METHOD = "authenticatedRpc";
+ public static final String METHOD = "authenticatedRpc";
+ /**
+ * Create {@link AuthenticatedRpcRequest} from a template
+ * {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link AuthenticatedRpcRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static AuthenticatedRpcRequest from(JsonrpcRequest r) throws OpenemsNamedException {
JsonObject p = r.getParams();
User user = User.from(JsonUtils.getAsJsonObject(p, "user"));
JsonrpcRequest payload = GenericJsonrpcRequest.from(JsonUtils.getAsJsonObject(p, "payload"));
- return new AuthenticatedRpcRequest(r.getId(), user, payload);
+ return new AuthenticatedRpcRequest(r, user, payload);
}
private final User user;
private final JsonrpcRequest payload;
public AuthenticatedRpcRequest(User user, JsonrpcRequest payload) {
- this(UUID.randomUUID(), user, payload);
+ super(METHOD);
+ this.user = user;
+ this.payload = payload;
}
- public AuthenticatedRpcRequest(UUID id, User user, JsonrpcRequest payload) {
- super(id, METHOD);
+ private AuthenticatedRpcRequest(JsonrpcRequest request, User user, JsonrpcRequest payload) {
+ super(request, METHOD);
this.user = user;
this.payload = payload;
}
+ /**
+ * Gets the {@link User}.
+ *
+ * @return User
+ */
public User getUser() {
- return user;
+ return this.user;
}
+ /**
+ * Gets the Payload {@link JsonrpcRequest}.
+ *
+ * @return Payload
+ */
public JsonrpcRequest getPayload() {
- return payload;
+ return this.payload;
}
@Override
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/ComponentJsonApiRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/ComponentJsonApiRequest.java
index 02d95ad6460..6de9d8837ca 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/ComponentJsonApiRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/ComponentJsonApiRequest.java
@@ -1,7 +1,5 @@
package io.openems.common.jsonrpc.request;
-import java.util.UUID;
-
import com.google.gson.JsonObject;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
@@ -10,7 +8,7 @@
import io.openems.common.utils.JsonUtils;
/**
- * Wraps a JSON-RPC Request for an OpenEMS Component that implements JsonApi
+ * Wraps a JSON-RPC Request for an OpenEMS Component that implements JsonApi.
*
*
* {
@@ -26,24 +24,34 @@
*/
public class ComponentJsonApiRequest extends JsonrpcRequest {
+ public static final String METHOD = "componentJsonApi";
+
+ /**
+ * Create {@link ComponentJsonApiRequest} from a template
+ * {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link ComponentJsonApiRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static ComponentJsonApiRequest from(JsonrpcRequest r) throws OpenemsNamedException {
JsonObject p = r.getParams();
String componentId = JsonUtils.getAsString(p, "componentId");
JsonrpcRequest payload = GenericJsonrpcRequest.fromIgnoreId(JsonUtils.getAsJsonObject(p, "payload"));
- return new ComponentJsonApiRequest(r.getId(), componentId, payload);
+ return new ComponentJsonApiRequest(r, componentId, payload);
}
- public final static String METHOD = "componentJsonApi";
-
private final String componentId;
private final JsonrpcRequest payload;
public ComponentJsonApiRequest(String componentId, JsonrpcRequest payload) {
- this(UUID.randomUUID(), componentId, payload);
+ super(METHOD, payload.getTimeout() /* inherit timeout from payload */);
+ this.componentId = componentId;
+ this.payload = payload;
}
- public ComponentJsonApiRequest(UUID id, String componentId, JsonrpcRequest payload) {
- super(id, METHOD);
+ private ComponentJsonApiRequest(JsonrpcRequest request, String componentId, JsonrpcRequest payload) {
+ super(request, METHOD);
this.componentId = componentId;
this.payload = payload;
}
@@ -56,12 +64,22 @@ public JsonObject getParams() {
.build();
}
+ /**
+ * Gets the Component-ID.
+ *
+ * @return Component-ID
+ */
public String getComponentId() {
- return componentId;
+ return this.componentId;
}
+ /**
+ * Gets the Payload {@link JsonrpcRequest}.
+ *
+ * @return Payload
+ */
public JsonrpcRequest getPayload() {
- return payload;
+ return this.payload;
}
}
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/CreateComponentConfigRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/CreateComponentConfigRequest.java
index 616ab243718..2b467a31b79 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/CreateComponentConfigRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/CreateComponentConfigRequest.java
@@ -1,7 +1,6 @@
package io.openems.common.jsonrpc.request;
import java.util.List;
-import java.util.UUID;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
@@ -31,33 +30,47 @@
*/
public class CreateComponentConfigRequest extends JsonrpcRequest {
- public static CreateComponentConfigRequest from(JsonrpcRequest r) throws OpenemsNamedException {
- return CreateComponentConfigRequest.from(r.getId(), r.getParams());
- }
+ public static final String METHOD = "createComponentConfig";
- public static CreateComponentConfigRequest from(UUID id, JsonObject params) throws OpenemsNamedException {
- String factoryPid = JsonUtils.getAsString(params, "factoryPid");
- List properties = Property.from(JsonUtils.getAsJsonArray(params, "properties"));
- return new CreateComponentConfigRequest(id, factoryPid, properties);
+ /**
+ * Create {@link CreateComponentConfigRequest} from a template
+ * {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link CreateComponentConfigRequest}
+ * @throws OpenemsNamedException on parse error
+ */
+ public static CreateComponentConfigRequest from(JsonrpcRequest r) throws OpenemsNamedException {
+ JsonObject p = r.getParams();
+ String factoryPid = JsonUtils.getAsString(p, "factoryPid");
+ List properties = Property.from(JsonUtils.getAsJsonArray(p, "properties"));
+ return new CreateComponentConfigRequest(r, factoryPid, properties);
}
+ /**
+ * Create {@link CreateComponentConfigRequest} from a {@link JsonObject}.
+ *
+ * @param params the {@link JsonObject}
+ * @return the {@link CreateComponentConfigRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static CreateComponentConfigRequest from(JsonObject params) throws OpenemsNamedException {
String factoryPid = JsonUtils.getAsString(params, "factoryPid");
List properties = Property.from(JsonUtils.getAsJsonArray(params, "properties"));
return new CreateComponentConfigRequest(factoryPid, properties);
}
- public final static String METHOD = "createComponentConfig";
-
private final String factoryPid;
private final List properties;
public CreateComponentConfigRequest(String factoryPid, List properties) {
- this(UUID.randomUUID(), factoryPid, properties);
+ super(METHOD);
+ this.factoryPid = factoryPid;
+ this.properties = properties;
}
- public CreateComponentConfigRequest(UUID id, String factoryPid, List properties) {
- super(id, METHOD);
+ private CreateComponentConfigRequest(JsonrpcRequest request, String factoryPid, List properties) {
+ super(request, METHOD);
this.factoryPid = factoryPid;
this.properties = properties;
}
@@ -74,10 +87,20 @@ public JsonObject getParams() {
.build();
}
+ /**
+ * Gets the Factory-PID.
+ *
+ * @return Factory-PID
+ */
public String getFactoryPid() {
- return factoryPid;
+ return this.factoryPid;
}
+ /**
+ * Gets the Component-ID, or empty String if none is given.
+ *
+ * @return Component-ID
+ */
public String getComponentId() {
for (UpdateComponentConfigRequest.Property property : this.properties) {
if (property.getName().equals("id")) {
@@ -87,7 +110,12 @@ public String getComponentId() {
return "";
}
+ /**
+ * Gets the List of Properties.
+ *
+ * @return Properties
+ */
public List getProperties() {
- return properties;
+ return this.properties;
}
}
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/DeleteComponentConfigRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/DeleteComponentConfigRequest.java
index dffa8199573..3ce2f9080f8 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/DeleteComponentConfigRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/DeleteComponentConfigRequest.java
@@ -1,7 +1,5 @@
package io.openems.common.jsonrpc.request;
-import java.util.UUID;
-
import com.google.gson.JsonObject;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
@@ -24,22 +22,31 @@
*/
public class DeleteComponentConfigRequest extends JsonrpcRequest {
+ public static final String METHOD = "deleteComponentConfig";
+
+ /**
+ * Create {@link DeleteComponentConfigRequest} from a template
+ * {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link DeleteComponentConfigRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static DeleteComponentConfigRequest from(JsonrpcRequest r) throws OpenemsNamedException {
JsonObject p = r.getParams();
String componentId = JsonUtils.getAsString(p, "componentId");
- return new DeleteComponentConfigRequest(r.getId(), componentId);
+ return new DeleteComponentConfigRequest(r, componentId);
}
- public final static String METHOD = "deleteComponentConfig";
-
private final String componentId;
public DeleteComponentConfigRequest(String componentId) {
- this(UUID.randomUUID(), componentId);
+ super(METHOD);
+ this.componentId = componentId;
}
- public DeleteComponentConfigRequest(UUID id, String componentId) {
- super(id, METHOD);
+ private DeleteComponentConfigRequest(JsonrpcRequest request, String componentId) {
+ super(request, METHOD);
this.componentId = componentId;
}
@@ -50,7 +57,12 @@ public JsonObject getParams() {
.build();
}
+ /**
+ * Gets the Component-ID.
+ *
+ * @return Component-ID
+ */
public String getComponentId() {
- return componentId;
+ return this.componentId;
}
}
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/EdgeRpcRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/EdgeRpcRequest.java
index 34e2f8a2729..f815c05b4f8 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/EdgeRpcRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/EdgeRpcRequest.java
@@ -1,7 +1,5 @@
package io.openems.common.jsonrpc.request;
-import java.util.UUID;
-
import com.google.gson.JsonObject;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
@@ -27,34 +25,53 @@
*/
public class EdgeRpcRequest extends JsonrpcRequest {
- public final static String METHOD = "edgeRpc";
+ public static final String METHOD = "edgeRpc";
+ /**
+ * Create {@link EdgeRpcRequest} from a template {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link EdgeRpcRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static EdgeRpcRequest from(JsonrpcRequest r) throws OpenemsNamedException {
JsonObject p = r.getParams();
String edgeId = JsonUtils.getAsString(p, "edgeId");
JsonrpcRequest payload = GenericJsonrpcRequest.from(JsonUtils.getAsJsonObject(p, "payload"));
- return new EdgeRpcRequest(r.getId(), edgeId, payload);
+ return new EdgeRpcRequest(r, edgeId, payload);
}
private final String edgeId;
private final JsonrpcRequest payload;
public EdgeRpcRequest(String edgeId, JsonrpcRequest payload) {
- this(UUID.randomUUID(), edgeId, payload);
+ super(METHOD, payload.getTimeout() /* inherit timeout from payload */);
+ this.edgeId = edgeId;
+ this.payload = payload;
}
- public EdgeRpcRequest(UUID id, String edgeId, JsonrpcRequest payload) {
- super(id, METHOD);
+ public EdgeRpcRequest(JsonrpcRequest request, String edgeId, JsonrpcRequest payload) {
+ super(request, METHOD);
this.edgeId = edgeId;
this.payload = payload;
}
+ /**
+ * Gets the Edge-ID.
+ *
+ * @return Edge-ID
+ */
public String getEdgeId() {
- return edgeId;
+ return this.edgeId;
}
+ /**
+ * Gets the Payload {@link JsonrpcRequest}.
+ *
+ * @return Payload
+ */
public JsonrpcRequest getPayload() {
- return payload;
+ return this.payload;
}
@Override
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/GetEdgeConfigRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/GetEdgeConfigRequest.java
index 1a8ae619f83..f775ba6ae60 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/GetEdgeConfigRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/GetEdgeConfigRequest.java
@@ -1,9 +1,8 @@
package io.openems.common.jsonrpc.request;
-import java.util.UUID;
-
import com.google.gson.JsonObject;
+import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.common.exceptions.OpenemsException;
import io.openems.common.jsonrpc.base.JsonrpcRequest;
@@ -21,18 +20,21 @@
*/
public class GetEdgeConfigRequest extends JsonrpcRequest {
- public static GetEdgeConfigRequest from(JsonrpcRequest r) throws OpenemsException {
- return new GetEdgeConfigRequest(r.getId());
- }
+ public static final String METHOD = "getEdgeConfig";
- public final static String METHOD = "getEdgeConfig";
-
- public GetEdgeConfigRequest() {
- this(UUID.randomUUID());
+ /**
+ * Create {@link GetEdgeConfigRequest} from a template {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link GetEdgeConfigRequest}
+ * @throws OpenemsNamedException on parse error
+ */
+ public static GetEdgeConfigRequest from(JsonrpcRequest r) throws OpenemsException {
+ return new GetEdgeConfigRequest(r);
}
- public GetEdgeConfigRequest(UUID id) {
- super(id, METHOD);
+ private GetEdgeConfigRequest(JsonrpcRequest request) {
+ super(request, METHOD);
}
@Override
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesDataRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesDataRequest.java
index 08c5f62819b..595491e2b1b 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesDataRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesDataRequest.java
@@ -6,17 +6,15 @@
import java.time.format.DateTimeFormatter;
import java.util.Optional;
import java.util.TreeSet;
-import java.util.UUID;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
-import io.openems.common.exceptions.OpenemsException;
-import io.openems.common.jsonrpc.base.GenericJsonrpcRequest;
import io.openems.common.jsonrpc.base.JsonrpcRequest;
import io.openems.common.types.ChannelAddress;
+import io.openems.common.utils.DateUtils;
import io.openems.common.utils.JsonUtils;
/**
@@ -39,10 +37,16 @@
*/
public class QueryHistoricTimeseriesDataRequest extends JsonrpcRequest {
- public final static String METHOD = "queryHistoricTimeseriesData";
-
- private final static DateTimeFormatter FORMAT = DateTimeFormatter.ISO_LOCAL_DATE;
+ public static final String METHOD = "queryHistoricTimeseriesData";
+ /**
+ * Create {@link QueryHistoricTimeseriesDataRequest} from a template
+ * {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link QueryHistoricTimeseriesDataRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static QueryHistoricTimeseriesDataRequest from(JsonrpcRequest r) throws OpenemsNamedException {
JsonObject p = r.getParams();
int timezoneDiff = JsonUtils.getAsInt(p, "timezone");
@@ -50,7 +54,7 @@ public static QueryHistoricTimeseriesDataRequest from(JsonrpcRequest r) throws O
ZonedDateTime fromDate = JsonUtils.getAsZonedDateTime(p, "fromDate", timezone);
ZonedDateTime toDate = JsonUtils.getAsZonedDateTime(p, "toDate", timezone).plusDays(1);
Integer resolution = JsonUtils.getAsOptionalInt(p, "resolution").orElse(null);
- QueryHistoricTimeseriesDataRequest result = new QueryHistoricTimeseriesDataRequest(r.getId(), fromDate, toDate,
+ QueryHistoricTimeseriesDataRequest result = new QueryHistoricTimeseriesDataRequest(r, fromDate, toDate,
resolution);
JsonArray channels = JsonUtils.getAsJsonArray(p, "channels");
for (JsonElement channel : channels) {
@@ -60,9 +64,7 @@ public static QueryHistoricTimeseriesDataRequest from(JsonrpcRequest r) throws O
return result;
}
- public static QueryHistoricTimeseriesDataRequest from(JsonObject j) throws OpenemsNamedException {
- return from(GenericJsonrpcRequest.from(j));
- }
+ private static final DateTimeFormatter FORMAT = DateTimeFormatter.ISO_LOCAL_DATE;
private final int timezoneDiff;
private final ZonedDateTime fromDate;
@@ -74,15 +76,12 @@ public static QueryHistoricTimeseriesDataRequest from(JsonObject j) throws Opene
*/
private final Integer resolution;
- public QueryHistoricTimeseriesDataRequest(UUID id, ZonedDateTime fromDate, ZonedDateTime toDate, Integer resolution)
- throws OpenemsNamedException {
- super(id, METHOD);
+ private QueryHistoricTimeseriesDataRequest(JsonrpcRequest request, ZonedDateTime fromDate, ZonedDateTime toDate,
+ Integer resolution) throws OpenemsNamedException {
+ super(request, METHOD);
+ DateUtils.assertSameTimezone(fromDate, toDate);
this.timezoneDiff = ZoneOffset.from(fromDate).getTotalSeconds();
- if (timezoneDiff != ZoneOffset.from(toDate).getTotalSeconds()) {
- throw new OpenemsException("FromDate and ToDate need to be in the same timezone!");
- }
-
this.fromDate = fromDate;
this.toDate = toDate;
this.resolution = resolution;
@@ -90,7 +89,13 @@ public QueryHistoricTimeseriesDataRequest(UUID id, ZonedDateTime fromDate, Zoned
public QueryHistoricTimeseriesDataRequest(ZonedDateTime fromDate, ZonedDateTime toDate, Integer resolution)
throws OpenemsNamedException {
- this(UUID.randomUUID(), fromDate, toDate, resolution);
+ super(METHOD);
+
+ DateUtils.assertSameTimezone(fromDate, toDate);
+ this.timezoneDiff = ZoneOffset.from(fromDate).getTotalSeconds();
+ this.fromDate = fromDate;
+ this.toDate = toDate;
+ this.resolution = resolution;
}
private void addChannel(ChannelAddress address) {
@@ -112,20 +117,40 @@ public JsonObject getParams() {
.build();
}
+ /**
+ * Gets the From-Date.
+ *
+ * @return From-Date
+ */
public ZonedDateTime getFromDate() {
- return fromDate;
+ return this.fromDate;
}
+ /**
+ * Gets the To-Date.
+ *
+ * @return To-Date
+ */
public ZonedDateTime getToDate() {
- return toDate;
+ return this.toDate;
}
+ /**
+ * Gets the {@link ChannelAddress}es.
+ *
+ * @return Set of {@link ChannelAddress}
+ */
public TreeSet getChannels() {
- return channels;
+ return this.channels;
}
+ /**
+ * Gets the requested Resolution in [s].
+ *
+ * @return Resolution
+ */
public Optional getResolution() {
- return Optional.ofNullable(resolution);
+ return Optional.ofNullable(this.resolution);
}
}
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesEnergyPerPeriodRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesEnergyPerPeriodRequest.java
index 26bc80fde69..a29a704cacb 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesEnergyPerPeriodRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesEnergyPerPeriodRequest.java
@@ -5,17 +5,15 @@
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.TreeSet;
-import java.util.UUID;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
-import io.openems.common.exceptions.OpenemsException;
-import io.openems.common.jsonrpc.base.GenericJsonrpcRequest;
import io.openems.common.jsonrpc.base.JsonrpcRequest;
import io.openems.common.types.ChannelAddress;
+import io.openems.common.utils.DateUtils;
import io.openems.common.utils.JsonUtils;
/**
@@ -45,10 +43,16 @@
public class QueryHistoricTimeseriesEnergyPerPeriodRequest extends JsonrpcRequest {
- public final static String METHOD = "queryHistoricTimeseriesEnergyPerPeriod";
-
- private final static DateTimeFormatter FORMAT = DateTimeFormatter.ISO_LOCAL_DATE;
+ public static final String METHOD = "queryHistoricTimeseriesEnergyPerPeriod";
+ /**
+ * Create {@link QueryHistoricTimeseriesEnergyPerPeriodRequest} from a template
+ * {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link QueryHistoricTimeseriesEnergyPerPeriodRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static QueryHistoricTimeseriesEnergyPerPeriodRequest from(JsonrpcRequest r) throws OpenemsNamedException {
JsonObject p = r.getParams();
int timezoneDiff = JsonUtils.getAsInt(p, "timezone");
@@ -56,7 +60,7 @@ public static QueryHistoricTimeseriesEnergyPerPeriodRequest from(JsonrpcRequest
ZonedDateTime fromDate = JsonUtils.getAsZonedDateTime(p, "fromDate", timezone);
ZonedDateTime toDate = JsonUtils.getAsZonedDateTime(p, "toDate", timezone).plusDays(1);
int resolution = JsonUtils.getAsInt(p, "resolution");
- QueryHistoricTimeseriesEnergyPerPeriodRequest result = new QueryHistoricTimeseriesEnergyPerPeriodRequest(r.getId(),
+ QueryHistoricTimeseriesEnergyPerPeriodRequest result = new QueryHistoricTimeseriesEnergyPerPeriodRequest(r,
fromDate, toDate, resolution);
JsonArray channels = JsonUtils.getAsJsonArray(p, "channels");
for (JsonElement channel : channels) {
@@ -66,9 +70,7 @@ public static QueryHistoricTimeseriesEnergyPerPeriodRequest from(JsonrpcRequest
return result;
}
- public static QueryHistoricTimeseriesEnergyPerPeriodRequest from(JsonObject j) throws OpenemsNamedException {
- return from(GenericJsonrpcRequest.from(j));
- }
+ private static final DateTimeFormatter FORMAT = DateTimeFormatter.ISO_LOCAL_DATE;
private final int timezoneDiff;
private final ZonedDateTime fromDate;
@@ -76,15 +78,12 @@ public static QueryHistoricTimeseriesEnergyPerPeriodRequest from(JsonObject j) t
private final TreeSet channels = new TreeSet<>();
private final int resolution;
- public QueryHistoricTimeseriesEnergyPerPeriodRequest(UUID id, ZonedDateTime fromDate, ZonedDateTime toDate,
- int resolution) throws OpenemsNamedException {
- super(id, METHOD);
+ private QueryHistoricTimeseriesEnergyPerPeriodRequest(JsonrpcRequest request, ZonedDateTime fromDate,
+ ZonedDateTime toDate, int resolution) throws OpenemsNamedException {
+ super(request, METHOD);
+ DateUtils.assertSameTimezone(fromDate, toDate);
this.timezoneDiff = ZoneOffset.from(fromDate).getTotalSeconds();
- if (timezoneDiff != ZoneOffset.from(toDate).getTotalSeconds()) {
- throw new OpenemsException("FromDate and ToDate need to be in the same timezone!");
- }
-
this.fromDate = fromDate;
this.toDate = toDate;
this.resolution = resolution;
@@ -92,7 +91,13 @@ public QueryHistoricTimeseriesEnergyPerPeriodRequest(UUID id, ZonedDateTime from
public QueryHistoricTimeseriesEnergyPerPeriodRequest(ZonedDateTime fromDate, ZonedDateTime toDate, int resolution)
throws OpenemsNamedException {
- this(UUID.randomUUID(), fromDate, toDate, resolution);
+ super(METHOD);
+
+ DateUtils.assertSameTimezone(fromDate, toDate);
+ this.timezoneDiff = ZoneOffset.from(fromDate).getTotalSeconds();
+ this.fromDate = fromDate;
+ this.toDate = toDate;
+ this.resolution = resolution;
}
private void addChannel(ChannelAddress address) {
@@ -109,23 +114,43 @@ public JsonObject getParams() {
.addProperty("fromDate", FORMAT.format(this.fromDate)) //
.addProperty("toDate", FORMAT.format(this.toDate)) //
.add("channels", channels) //
- .addProperty("resolution", resolution) //
+ .addProperty("resolution", this.resolution) //
.build();
}
+ /**
+ * Gets the From-Date.
+ *
+ * @return From-Date
+ */
public ZonedDateTime getFromDate() {
- return fromDate;
+ return this.fromDate;
}
+ /**
+ * Gets the To-Date.
+ *
+ * @return To-Date
+ */
public ZonedDateTime getToDate() {
- return toDate;
+ return this.toDate;
}
+ /**
+ * Gets the {@link ChannelAddress}es.
+ *
+ * @return Set of {@link ChannelAddress}
+ */
public TreeSet getChannels() {
- return channels;
+ return this.channels;
}
+ /**
+ * Gets the requested Resolution in [s].
+ *
+ * @return Resolution
+ */
public int getResolution() {
- return resolution;
+ return this.resolution;
}
}
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesEnergyRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesEnergyRequest.java
index 21d70b6ea80..a5bf7e05ee2 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesEnergyRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesEnergyRequest.java
@@ -5,17 +5,15 @@
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.TreeSet;
-import java.util.UUID;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
-import io.openems.common.exceptions.OpenemsException;
-import io.openems.common.jsonrpc.base.GenericJsonrpcRequest;
import io.openems.common.jsonrpc.base.JsonrpcRequest;
import io.openems.common.types.ChannelAddress;
+import io.openems.common.utils.DateUtils;
import io.openems.common.utils.JsonUtils;
/**
@@ -44,18 +42,23 @@
public class QueryHistoricTimeseriesEnergyRequest extends JsonrpcRequest {
- public final static String METHOD = "queryHistoricTimeseriesEnergy";
-
- private final static DateTimeFormatter FORMAT = DateTimeFormatter.ISO_LOCAL_DATE;
+ public static final String METHOD = "queryHistoricTimeseriesEnergy";
+ /**
+ * Create {@link AuthenticateWithPasswordRequest} from a template
+ * {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link AuthenticateWithPasswordRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static QueryHistoricTimeseriesEnergyRequest from(JsonrpcRequest r) throws OpenemsNamedException {
JsonObject p = r.getParams();
int timezoneDiff = JsonUtils.getAsInt(p, "timezone");
ZoneId timezone = ZoneId.ofOffset("", ZoneOffset.ofTotalSeconds(timezoneDiff * -1));
ZonedDateTime fromDate = JsonUtils.getAsZonedDateTime(p, "fromDate", timezone);
ZonedDateTime toDate = JsonUtils.getAsZonedDateTime(p, "toDate", timezone).plusDays(1);
- QueryHistoricTimeseriesEnergyRequest result = new QueryHistoricTimeseriesEnergyRequest(r.getId(), fromDate,
- toDate);
+ QueryHistoricTimeseriesEnergyRequest result = new QueryHistoricTimeseriesEnergyRequest(r, fromDate, toDate);
JsonArray channels = JsonUtils.getAsJsonArray(p, "channels");
for (JsonElement channel : channels) {
ChannelAddress address = ChannelAddress.fromString(JsonUtils.getAsString(channel));
@@ -64,31 +67,31 @@ public static QueryHistoricTimeseriesEnergyRequest from(JsonrpcRequest r) throws
return result;
}
- public static QueryHistoricTimeseriesEnergyRequest from(JsonObject j) throws OpenemsNamedException {
- return from(GenericJsonrpcRequest.from(j));
- }
+ private static final DateTimeFormatter FORMAT = DateTimeFormatter.ISO_LOCAL_DATE;
private final int timezoneDiff;
private final ZonedDateTime fromDate;
private final ZonedDateTime toDate;
private final TreeSet channels = new TreeSet<>();
- public QueryHistoricTimeseriesEnergyRequest(UUID id, ZonedDateTime fromDate, ZonedDateTime toDate)
+ private QueryHistoricTimeseriesEnergyRequest(JsonrpcRequest request, ZonedDateTime fromDate, ZonedDateTime toDate)
throws OpenemsNamedException {
- super(id, METHOD);
+ super(request, METHOD);
+ DateUtils.assertSameTimezone(fromDate, toDate);
this.timezoneDiff = ZoneOffset.from(fromDate).getTotalSeconds();
- if (timezoneDiff != ZoneOffset.from(toDate).getTotalSeconds()) {
- throw new OpenemsException("FromDate and ToDate need to be in the same timezone!");
- }
-
this.fromDate = fromDate;
this.toDate = toDate;
}
public QueryHistoricTimeseriesEnergyRequest(ZonedDateTime fromDate, ZonedDateTime toDate)
throws OpenemsNamedException {
- this(UUID.randomUUID(), fromDate, toDate);
+ super(METHOD);
+
+ DateUtils.assertSameTimezone(fromDate, toDate);
+ this.timezoneDiff = ZoneOffset.from(fromDate).getTotalSeconds();
+ this.fromDate = fromDate;
+ this.toDate = toDate;
}
private void addChannel(ChannelAddress address) {
@@ -108,15 +111,31 @@ public JsonObject getParams() {
.build();
}
+ /**
+ * Gets the From-Date.
+ *
+ * @return From-Date
+ */
public ZonedDateTime getFromDate() {
- return fromDate;
+ return this.fromDate;
}
+ /**
+ * Gets the To-Date.
+ *
+ * @return To-Date
+ */
public ZonedDateTime getToDate() {
- return toDate;
+ return this.toDate;
}
+ /**
+ * Gets the {@link ChannelAddress}es.
+ *
+ * @return Set of {@link ChannelAddress}
+ */
public TreeSet getChannels() {
- return channels;
+ return this.channels;
}
+
}
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesExportXlxsRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesExportXlxsRequest.java
index 65ac6eaceb2..87f67f64adf 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesExportXlxsRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/QueryHistoricTimeseriesExportXlxsRequest.java
@@ -4,13 +4,12 @@
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
-import java.util.UUID;
import com.google.gson.JsonObject;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
-import io.openems.common.exceptions.OpenemsException;
import io.openems.common.jsonrpc.base.JsonrpcRequest;
+import io.openems.common.utils.DateUtils;
import io.openems.common.utils.JsonUtils;
/**
@@ -33,33 +32,38 @@ public class QueryHistoricTimeseriesExportXlxsRequest extends JsonrpcRequest {
public static final String METHOD = "queryHistoricTimeseriesExportXlxs";
- private static final DateTimeFormatter FORMAT = DateTimeFormatter.ISO_LOCAL_DATE;
-
+ /**
+ * Create {@link QueryHistoricTimeseriesExportXlxsRequest} from a template
+ * {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link QueryHistoricTimeseriesExportXlxsRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static QueryHistoricTimeseriesExportXlxsRequest from(JsonrpcRequest r) throws OpenemsNamedException {
JsonObject p = r.getParams();
int timezoneDiff = JsonUtils.getAsInt(p, "timezone");
ZoneId timezone = ZoneId.ofOffset("", ZoneOffset.ofTotalSeconds(timezoneDiff * -1));
ZonedDateTime fromDate = JsonUtils.getAsZonedDateTime(p, "fromDate", timezone);
ZonedDateTime toDate = JsonUtils.getAsZonedDateTime(p, "toDate", timezone).plusDays(1);
- QueryHistoricTimeseriesExportXlxsRequest result = new QueryHistoricTimeseriesExportXlxsRequest(r.getId(),
- fromDate, toDate);
+ QueryHistoricTimeseriesExportXlxsRequest result = new QueryHistoricTimeseriesExportXlxsRequest(r, fromDate,
+ toDate);
return result;
}
+ private static final DateTimeFormatter FORMAT = DateTimeFormatter.ISO_LOCAL_DATE;
+
private final int timezoneDiff;
private final ZonedDateTime fromDate;
private final ZonedDateTime toDate;
- public QueryHistoricTimeseriesExportXlxsRequest(UUID id, ZonedDateTime fromDate, ZonedDateTime toDate)
- throws OpenemsNamedException {
- super(id, METHOD);
+ private QueryHistoricTimeseriesExportXlxsRequest(JsonrpcRequest request, ZonedDateTime fromDate,
+ ZonedDateTime toDate) throws OpenemsNamedException {
+ super(request, METHOD);
+ DateUtils.assertSameTimezone(fromDate, toDate);
this.timezoneDiff = ZoneOffset.from(fromDate).getTotalSeconds();
- if (this.timezoneDiff != ZoneOffset.from(toDate).getTotalSeconds()) {
- throw new OpenemsException("FromDate and ToDate need to be in the same timezone!");
- }
-
this.fromDate = fromDate;
this.toDate = toDate;
}
@@ -73,10 +77,20 @@ public JsonObject getParams() {
.build();
}
+ /**
+ * Gets the From-Date.
+ *
+ * @return From-Date
+ */
public ZonedDateTime getFromDate() {
return this.fromDate;
}
+ /**
+ * Gets the To-Date.
+ *
+ * @return To-Date
+ */
public ZonedDateTime getToDate() {
return this.toDate;
}
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/SetChannelValueRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/SetChannelValueRequest.java
index a5a22764dd9..c85a4aa382c 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/SetChannelValueRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/SetChannelValueRequest.java
@@ -1,7 +1,5 @@
package io.openems.common.jsonrpc.request;
-import java.util.UUID;
-
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -28,26 +26,36 @@
*/
public class SetChannelValueRequest extends JsonrpcRequest {
+ public static final String METHOD = "setChannelValue";
+
+ /**
+ * Create {@link SetChannelValueRequest} from a template {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link SetChannelValueRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static SetChannelValueRequest from(JsonrpcRequest r) throws OpenemsNamedException {
JsonObject p = r.getParams();
String componentId = JsonUtils.getAsString(p, "componentId");
String channelId = JsonUtils.getAsString(p, "channelId");
JsonElement value = JsonUtils.getSubElement(p, "value");
- return new SetChannelValueRequest(r.getId(), componentId, channelId, value);
+ return new SetChannelValueRequest(r, componentId, channelId, value);
}
- public final static String METHOD = "setChannelValue";
-
private final String componentId;
private final String channelId;
private final JsonElement value;
public SetChannelValueRequest(String componentId, String channelId, JsonElement value) {
- this(UUID.randomUUID(), componentId, channelId, value);
+ super(METHOD);
+ this.componentId = componentId;
+ this.channelId = channelId;
+ this.value = value;
}
- public SetChannelValueRequest(UUID id, String componentId, String channelId, JsonElement value) {
- super(id, METHOD);
+ private SetChannelValueRequest(JsonrpcRequest request, String componentId, String channelId, JsonElement value) {
+ super(request, METHOD);
this.componentId = componentId;
this.channelId = channelId;
this.value = value;
@@ -62,19 +70,39 @@ public JsonObject getParams() {
.build();
}
+ /**
+ * Gets the Component-ID.
+ *
+ * @return Component-ID
+ */
public String getComponentId() {
- return componentId;
+ return this.componentId;
}
+ /**
+ * Gets the Channel-ID.
+ *
+ * @return Channel-ID
+ */
public String getChannelId() {
- return channelId;
+ return this.channelId;
}
+ /**
+ * Gets the {@link ChannelAddress}.
+ *
+ * @return ChannelAddress
+ */
public ChannelAddress getChannelAddress() {
return new ChannelAddress(this.componentId, this.channelId);
}
+ /**
+ * Gets the Value.
+ *
+ * @return Value
+ */
public JsonElement getValue() {
- return value;
+ return this.value;
}
}
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/SetGridConnScheduleRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/SetGridConnScheduleRequest.java
index 8f6bf25079b..a85cc54eaa8 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/SetGridConnScheduleRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/SetGridConnScheduleRequest.java
@@ -3,7 +3,6 @@
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
-import java.util.UUID;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
@@ -34,12 +33,20 @@
*/
public class SetGridConnScheduleRequest extends JsonrpcRequest {
+ /**
+ * Create {@link SetGridConnScheduleRequest} from a template
+ * {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link SetGridConnScheduleRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static SetGridConnScheduleRequest from(JsonrpcRequest r) throws OpenemsNamedException {
JsonObject p = r.getParams();
String edgeId = JsonUtils.getAsString(p, "id");
JsonArray s = JsonUtils.getAsJsonArray(p, "schedule");
List schedule = GridConnSchedule.from(s);
- return new SetGridConnScheduleRequest(r.getId(), edgeId, schedule);
+ return new SetGridConnScheduleRequest(r, edgeId, schedule);
}
public static final String METHOD = "setGridConnSchedule";
@@ -48,19 +55,26 @@ public static SetGridConnScheduleRequest from(JsonrpcRequest r) throws OpenemsNa
private final List schedule;
public SetGridConnScheduleRequest(String edgeId) {
- this(UUID.randomUUID(), edgeId, new ArrayList<>());
+ this(edgeId, new ArrayList<>());
}
public SetGridConnScheduleRequest(String edgeId, List schedule) {
- this(UUID.randomUUID(), edgeId, schedule);
+ super(METHOD);
+ this.edgeId = edgeId;
+ this.schedule = schedule;
}
- public SetGridConnScheduleRequest(UUID id, String edgeId, List schedule) {
- super(id, METHOD);
+ private SetGridConnScheduleRequest(JsonrpcRequest request, String edgeId, List schedule) {
+ super(request, METHOD);
this.edgeId = edgeId;
this.schedule = schedule;
}
+ /**
+ * Add a {@link GridConnSchedule} entry.
+ *
+ * @param scheduleEntry GridConnSchedule entry
+ */
public void addScheduleEntry(GridConnSchedule scheduleEntry) {
this.schedule.add(scheduleEntry);
}
@@ -77,16 +91,33 @@ public JsonObject getParams() {
.build();
}
+ /**
+ * Gets the Edge-ID.
+ *
+ * @return Edge-ID
+ */
public String getEdgeId() {
return this.edgeId;
}
+ /**
+ * Gets the list of {@link GridConnSchedule} entries.
+ *
+ * @return entries
+ */
public List getSchedule() {
return this.schedule;
}
public static class GridConnSchedule {
+ /**
+ * Create a list of {@link GridConnSchedule}s from a {@link JsonArray}.
+ *
+ * @param j the {@link JsonArray}
+ * @return the list of {@link GridConnSchedule}s
+ * @throws OpenemsNamedException on parse error
+ */
public static List from(JsonArray j) throws OpenemsNamedException {
List schedule = new ArrayList<>();
for (JsonElement se : j) {
@@ -116,19 +147,34 @@ public GridConnSchedule(long startTimestamp, int duration, int activePowerSetPoi
this.activePowerSetPoint = activePowerSetPoint;
}
+ /**
+ * Gets the start timestamp in epoch seconds.
+ *
+ * @return start timestamp
+ */
public long getStartTimestamp() {
return this.startTimestamp;
}
+ /**
+ * Gets the duration in seconds.
+ *
+ * @return duration
+ */
public int getDuration() {
return this.duration;
}
+ /**
+ * Gets the Active-Power Setpoint.
+ *
+ * @return the setpoint
+ */
public int getActivePowerSetPoint() {
return this.activePowerSetPoint;
}
- public JsonObject toJson() {
+ protected JsonObject toJson() {
return JsonUtils.buildJsonObject() //
.addProperty("startTimestamp", this.getStartTimestamp()) //
.addProperty("duration", this.getDuration()) //
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/SubscribeChannelsRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/SubscribeChannelsRequest.java
index 19f476e3d34..6965ecfceab 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/SubscribeChannelsRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/SubscribeChannelsRequest.java
@@ -1,14 +1,12 @@
package io.openems.common.jsonrpc.request;
import java.util.TreeSet;
-import java.util.UUID;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
-import io.openems.common.jsonrpc.base.GenericJsonrpcRequest;
import io.openems.common.jsonrpc.base.JsonrpcRequest;
import io.openems.common.types.ChannelAddress;
import io.openems.common.utils.JsonUtils;
@@ -16,6 +14,7 @@
/**
* Represents a JSON-RPC Request to subscribe to Channels.
*
+ *
* This is used by UI to get regular updates on specific channels.
*
*
@@ -32,12 +31,20 @@
*/
public class SubscribeChannelsRequest extends JsonrpcRequest {
- public final static String METHOD = "subscribeChannels";
+ public static final String METHOD = "subscribeChannels";
+ /**
+ * Create {@link SubscribeChannelsRequest} from a template
+ * {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link SubscribeChannelsRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static SubscribeChannelsRequest from(JsonrpcRequest r) throws OpenemsNamedException {
JsonObject p = r.getParams();
int count = JsonUtils.getAsInt(p, "count");
- SubscribeChannelsRequest result = new SubscribeChannelsRequest(r.getId(), count);
+ SubscribeChannelsRequest result = new SubscribeChannelsRequest(r, count);
JsonArray channels = JsonUtils.getAsJsonArray(p, "channels");
for (JsonElement channel : channels) {
ChannelAddress address = ChannelAddress.fromString(JsonUtils.getAsString(channel));
@@ -46,32 +53,42 @@ public static SubscribeChannelsRequest from(JsonrpcRequest r) throws OpenemsName
return result;
}
- public static SubscribeChannelsRequest from(JsonObject j) throws OpenemsNamedException {
- return from(GenericJsonrpcRequest.from(j));
- }
-
private final int count;
private final TreeSet channels = new TreeSet<>();
- public SubscribeChannelsRequest(UUID id, int count) {
- super(id, METHOD);
+ private SubscribeChannelsRequest(JsonrpcRequest request, int count) {
+ super(request, METHOD);
this.count = count;
}
public SubscribeChannelsRequest(int count) {
- this(UUID.randomUUID(), count);
+ super(METHOD);
+ this.count = count;
}
private void addChannel(ChannelAddress address) {
this.channels.add(address);
}
+ /**
+ * Gets the Count value.
+ *
+ *
+ * This value is increased with every request to assure order.
+ *
+ * @return the count value
+ */
public int getCount() {
return this.count;
}
+ /**
+ * Gets the set of {@link ChannelAddress}es.
+ *
+ * @return the {@link ChannelAddress}es
+ */
public TreeSet getChannels() {
- return channels;
+ return this.channels;
}
@Override
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/SubscribeSystemLogRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/SubscribeSystemLogRequest.java
index 727b275c437..acc566f15cb 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/SubscribeSystemLogRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/SubscribeSystemLogRequest.java
@@ -1,11 +1,8 @@
package io.openems.common.jsonrpc.request;
-import java.util.UUID;
-
import com.google.gson.JsonObject;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
-import io.openems.common.jsonrpc.base.GenericJsonrpcRequest;
import io.openems.common.jsonrpc.base.JsonrpcRequest;
import io.openems.common.utils.JsonUtils;
@@ -32,35 +29,55 @@ public class SubscribeSystemLogRequest extends JsonrpcRequest {
public static final String METHOD = "subscribeSystemLog";
+ /**
+ * Create {@link SubscribeSystemLogRequest} from a template
+ * {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link SubscribeSystemLogRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static SubscribeSystemLogRequest from(JsonrpcRequest r) throws OpenemsNamedException {
JsonObject p = r.getParams();
boolean subscribe = JsonUtils.getAsBoolean(p, "subscribe");
- return new SubscribeSystemLogRequest(r.getId(), subscribe);
- }
-
- public static SubscribeSystemLogRequest from(JsonObject j) throws OpenemsNamedException {
- return from(GenericJsonrpcRequest.from(j));
+ return new SubscribeSystemLogRequest(r, subscribe);
}
+ /**
+ * Creates a JSON-RPC Request that subscribes the System-Log.
+ *
+ * @return {@link SubscribeSystemLogRequest}
+ */
public static SubscribeSystemLogRequest subscribe() {
return new SubscribeSystemLogRequest(true);
}
+ /**
+ * Creates a JSON-RPC Request that unsubscribes the System-Log.
+ *
+ * @return {@link SubscribeSystemLogRequest}
+ */
public static SubscribeSystemLogRequest unsubscribe() {
return new SubscribeSystemLogRequest(false);
}
private final boolean subscribe;
- private SubscribeSystemLogRequest(UUID id, boolean subscribe) {
- super(id, METHOD);
+ private SubscribeSystemLogRequest(JsonrpcRequest request, boolean subscribe) {
+ super(request, METHOD);
this.subscribe = subscribe;
}
public SubscribeSystemLogRequest(boolean subscribe) {
- this(UUID.randomUUID(), subscribe);
+ super(METHOD);
+ this.subscribe = subscribe;
}
+ /**
+ * Whether to subscribe or unsubscribe.
+ *
+ * @return true for subscribe, false for unsubscribe
+ */
public boolean getSubscribe() {
return this.subscribe;
}
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/request/UpdateComponentConfigRequest.java b/io.openems.common/src/io/openems/common/jsonrpc/request/UpdateComponentConfigRequest.java
index 614e87bb373..7680bbb16b9 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/request/UpdateComponentConfigRequest.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/request/UpdateComponentConfigRequest.java
@@ -2,7 +2,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.UUID;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
@@ -33,24 +32,34 @@
*/
public class UpdateComponentConfigRequest extends JsonrpcRequest {
+ public static final String METHOD = "updateComponentConfig";
+
+ /**
+ * Create {@link UpdateComponentConfigRequest} from a template
+ * {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link UpdateComponentConfigRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static UpdateComponentConfigRequest from(JsonrpcRequest r) throws OpenemsNamedException {
JsonObject p = r.getParams();
String componentId = JsonUtils.getAsString(p, "componentId");
List properties = Property.from(JsonUtils.getAsJsonArray(p, "properties"));
- return new UpdateComponentConfigRequest(r.getId(), componentId, properties);
+ return new UpdateComponentConfigRequest(r, componentId, properties);
}
- public final static String METHOD = "updateComponentConfig";
-
private final String componentId;
private final List properties;
public UpdateComponentConfigRequest(String componentId, List properties) {
- this(UUID.randomUUID(), componentId, properties);
+ super(METHOD);
+ this.componentId = componentId;
+ this.properties = properties;
}
- public UpdateComponentConfigRequest(UUID id, String componentId, List properties) {
- super(id, METHOD);
+ private UpdateComponentConfigRequest(JsonrpcRequest request, String componentId, List properties) {
+ super(request, METHOD);
this.componentId = componentId;
this.properties = properties;
}
@@ -67,17 +76,27 @@ public JsonObject getParams() {
.build();
}
+ /**
+ * Gets the Component-ID.
+ *
+ * @return Component-ID
+ */
public String getComponentId() {
- return componentId;
+ return this.componentId;
}
+ /**
+ * Gets a list of Properties.
+ *
+ * @return the Properties
+ */
public List getProperties() {
return this.properties;
}
public static class Property {
- public static List from(JsonArray j) throws OpenemsNamedException {
+ protected static List from(JsonArray j) throws OpenemsNamedException {
List properties = new ArrayList<>();
for (JsonElement property : j) {
String name = JsonUtils.getAsString(property, "name");
@@ -91,6 +110,8 @@ public static List from(JsonArray j) throws OpenemsNamedException {
private final JsonElement value;
/**
+ * Initializes a Property.
+ *
* @param name the Property name
* @param value the new value
*/
@@ -112,15 +133,25 @@ public Property(String name, Number value) {
this(name, new JsonPrimitive(value));
}
+ /**
+ * Gets the Name.
+ *
+ * @return Name
+ */
public String getName() {
return this.name;
}
+ /**
+ * Gets the Value.
+ *
+ * @return Value
+ */
public JsonElement getValue() {
return this.value;
}
- public JsonObject toJson() {
+ protected JsonObject toJson() {
return JsonUtils.buildJsonObject() //
.addProperty("name", this.getName()) //
.add("value", this.getValue()) //
diff --git a/io.openems.common/src/io/openems/common/jsonrpc/response/AuthenticateWithPasswordResponse.java b/io.openems.common/src/io/openems/common/jsonrpc/response/AuthenticateWithPasswordResponse.java
index 9f32b634e2f..44d52373a94 100644
--- a/io.openems.common/src/io/openems/common/jsonrpc/response/AuthenticateWithPasswordResponse.java
+++ b/io.openems.common/src/io/openems/common/jsonrpc/response/AuthenticateWithPasswordResponse.java
@@ -17,7 +17,7 @@
* "jsonrpc": "2.0",
* "id": "UUID",
* "result": {
- * "token": UUID,
+ * "token": String,
* "edges": {@link EdgeMetadata#toJson(java.util.Collection)}
* }
* }
@@ -25,27 +25,27 @@
*/
public class AuthenticateWithPasswordResponse extends JsonrpcResponseSuccess {
- private final UUID token;
+ private final String token;
private final List metadatas;
- public AuthenticateWithPasswordResponse(UUID id, UUID token, List metadatas) {
+ public AuthenticateWithPasswordResponse(UUID id, String token, List metadatas) {
super(id);
this.token = token;
this.metadatas = metadatas;
}
- public UUID getToken() {
- return token;
+ public String getToken() {
+ return this.token;
}
public List getMetadatas() {
- return metadatas;
+ return this.metadatas;
}
@Override
public JsonObject getResult() {
return JsonUtils.buildJsonObject() //
- .addProperty("token", this.token.toString()) //
+ .addProperty("token", this.token) //
.add("edges", EdgeMetadata.toJson(this.metadatas)) //
.build();
}
diff --git a/io.openems.common/src/io/openems/common/utils/DateUtils.java b/io.openems.common/src/io/openems/common/utils/DateUtils.java
new file mode 100644
index 00000000000..ed85a2da403
--- /dev/null
+++ b/io.openems.common/src/io/openems/common/utils/DateUtils.java
@@ -0,0 +1,25 @@
+package io.openems.common.utils;
+
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+
+import io.openems.common.exceptions.OpenemsException;
+
+public class DateUtils {
+
+ private DateUtils() {
+ }
+
+ /**
+ * Asserts that both dates are in the same timezone.
+ *
+ * @param date1 the first Date
+ * @param date1 the second Date
+ * @throws OpenemsException if dates are not in the same timezone
+ */
+ public static void assertSameTimezone(ZonedDateTime date1, ZonedDateTime date2) throws OpenemsException {
+ if (ZoneOffset.from(date1).getTotalSeconds() != ZoneOffset.from(date2).getTotalSeconds()) {
+ throw new OpenemsException("FromDate and ToDate need to be in the same timezone!");
+ }
+ }
+}
diff --git a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocket.java b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocket.java
index ca2f5c649e8..5a9a7820d6e 100644
--- a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocket.java
+++ b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocket.java
@@ -1,13 +1,31 @@
package io.openems.common.websocket;
-import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public abstract class AbstractWebsocket {
+ private final Logger log = LoggerFactory.getLogger(AbstractWebsocket.class);
private final String name;
+ /**
+ * Shared {@link ExecutorService}. Configuration is equal to
+ * Executors.newCachedThreadPool(), but with DiscardOldestPolicy.
+ */
+ private final ThreadPoolExecutor executor;
+
+ /*
+ * This Executor is used if Debug-Mode is activated.
+ */
+ private final ScheduledExecutorService debugLogExecutor;
+
/**
* Creates an empty WsData object that is attached to the WebSocket as early as
* possible
@@ -58,8 +76,30 @@ public abstract class AbstractWebsocket {
*/
protected abstract OnClose getOnClose();
- public AbstractWebsocket(String name) {
+ /**
+ * Construct this {@link AbstractWebsocket}.
+ *
+ * @param name a name that is used to identify log messages
+ * @param poolSize number of threads dedicated to handle the tasks
+ * @param debugMode activate a regular debug log about the state of the tasks
+ */
+ public AbstractWebsocket(String name, int poolSize, boolean debugMode) {
this.name = name;
+ this.executor = new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue());
+ if (debugMode) {
+ this.debugLogExecutor = Executors.newSingleThreadScheduledExecutor();
+ this.debugLogExecutor.scheduleWithFixedDelay(() -> {
+ this.logInfo(this.log,
+ String.format("[monitor] Pool: %d, Active: %d, Pending: %d, Completed: %d",
+ this.executor.getPoolSize(), //
+ this.executor.getActiveCount(), //
+ this.executor.getQueue().size(), //
+ this.executor.getCompletedTaskCount())); //
+ }, 10, 10, TimeUnit.SECONDS);
+ } else {
+ this.debugLogExecutor = null;
+ }
}
/**
@@ -71,13 +111,46 @@ public String getName() {
return name;
}
+ protected void start() {
+
+ }
+
+ public void stop() {
+ // Shutdown executor
+ if (this.executor != null) {
+ try {
+ this.executor.shutdown();
+ this.executor.awaitTermination(5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ this.logWarn(this.log, "tasks interrupted");
+ } finally {
+ if (!this.executor.isTerminated()) {
+ this.logWarn(this.log, "cancel non-finished tasks");
+ }
+ this.executor.shutdownNow();
+ }
+ }
+ if (this.debugLogExecutor != null) {
+ this.debugLogExecutor.shutdown();
+ }
+ }
+
+ /**
+ * Execute a {@link Runnable} using the shared {@link ExecutorService}.
+ *
+ * @param command the {@link Runnable}
+ */
+ protected void execute(Runnable command) {
+ this.executor.execute(command);
+ }
+
/**
* Handles an internal Error asynchronously
*
* @param e
*/
protected void handleInternalErrorAsync(Exception e) {
- CompletableFuture.runAsync(new OnInternalErrorHandler(this.getOnInternalError(), e));
+ this.execute(new OnInternalErrorHandler(this.getOnInternalError(), e));
}
/**
diff --git a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketClient.java b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketClient.java
index 7837ccaeccd..fd68be541e8 100644
--- a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketClient.java
+++ b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketClient.java
@@ -38,6 +38,8 @@ public abstract class AbstractWebsocketClient extends Abstract
public final static Proxy NO_PROXY = null;
public final static Draft DEFAULT_DRAFT = new Draft_6455();
+ private final static int MAXIMUM_POOL_SIZE = 10;
+
protected final WebSocketClient ws;
private final Logger log = LoggerFactory.getLogger(AbstractWebsocketClient.class);
@@ -58,14 +60,14 @@ protected AbstractWebsocketClient(String name, URI serverUri, Map httpHeaders,
Proxy proxy) {
- super(name);
+ super(name, MAXIMUM_POOL_SIZE, false /* debugMode */);
this.serverUri = serverUri;
this.ws = new WebSocketClient(serverUri, draft, httpHeaders) {
@Override
public void onOpen(ServerHandshake handshake) {
JsonObject jHandshake = WebsocketUtils.handshakeToJsonObject(handshake);
- CompletableFuture.runAsync(
+ AbstractWebsocketClient.this.execute(
new OnOpenHandler(AbstractWebsocketClient.this, AbstractWebsocketClient.this.ws, jHandshake));
}
@@ -74,17 +76,17 @@ public void onMessage(String stringMessage) {
try {
JsonrpcMessage message = JsonrpcMessage.from(stringMessage);
if (message instanceof JsonrpcRequest) {
- CompletableFuture.runAsync(new OnRequestHandler(AbstractWebsocketClient.this, ws,
+ AbstractWebsocketClient.this.execute(new OnRequestHandler(AbstractWebsocketClient.this, ws,
(JsonrpcRequest) message, (response) -> {
AbstractWebsocketClient.this.sendMessage(response);
}));
} else if (message instanceof JsonrpcResponse) {
- CompletableFuture.runAsync(
+ AbstractWebsocketClient.this.execute(
new OnResponseHandler(AbstractWebsocketClient.this, ws, (JsonrpcResponse) message));
} else if (message instanceof JsonrpcNotification) {
- CompletableFuture.runAsync(new OnNotificationHandler(AbstractWebsocketClient.this, ws,
+ AbstractWebsocketClient.this.execute(new OnNotificationHandler(AbstractWebsocketClient.this, ws,
(JsonrpcNotification) message));
}
@@ -95,12 +97,13 @@ public void onMessage(String stringMessage) {
@Override
public void onError(Exception ex) {
- CompletableFuture.runAsync(new OnErrorHandler(AbstractWebsocketClient.this, ws, ex));
+ AbstractWebsocketClient.this.execute(new OnErrorHandler(AbstractWebsocketClient.this, ws, ex));
}
@Override
public void onClose(int code, String reason, boolean remote) {
- CompletableFuture.runAsync(new OnCloseHandler(AbstractWebsocketClient.this, ws, code, reason, remote));
+ AbstractWebsocketClient.this
+ .execute(new OnCloseHandler(AbstractWebsocketClient.this, ws, code, reason, remote));
AbstractWebsocketClient.this.log.info(
"Websocket [" + serverUri.toString() + "] closed. Code [" + code + "] Reason [" + reason + "]");
@@ -118,7 +121,6 @@ public void onClose(int code, String reason, boolean remote) {
// Initialize reconnector
this.reconnectorWorker = new ClientReconnectorWorker(this);
- this.reconnectorWorker.activate(this.getName());
if (proxy != null) {
this.ws.setProxy(proxy);
@@ -131,6 +133,7 @@ public void onClose(int code, String reason, boolean remote) {
public void start() {
this.log.info("Opening connection [" + this.getName() + "] to websocket server [" + this.serverUri + "]");
this.ws.connect();
+ this.reconnectorWorker.activate(this.getName());
}
/**
diff --git a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketServer.java b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketServer.java
index 0c2ca1357cc..738c0eae000 100644
--- a/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketServer.java
+++ b/io.openems.common/src/io/openems/common/websocket/AbstractWebsocketServer.java
@@ -4,7 +4,6 @@
import java.net.BindException;
import java.net.InetSocketAddress;
import java.util.Collection;
-import java.util.concurrent.CompletableFuture;
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
@@ -28,11 +27,13 @@ public abstract class AbstractWebsocketServer extends Abstract
private final WebSocketServer ws;
/**
- * @param name to identify this server
- * @param port to listen on
+ * @param name to identify this server
+ * @param port to listen on
+ * @param poolSize number of threads dedicated to handle the tasks
+ * @param debugMode activate a regular debug log about the state of the tasks
*/
- protected AbstractWebsocketServer(String name, int port) {
- super(name);
+ protected AbstractWebsocketServer(String name, int port, int poolSize, boolean debugMode) {
+ super(name, poolSize, debugMode);
this.port = port;
this.ws = new WebSocketServer(new InetSocketAddress(port)) {
@@ -46,7 +47,7 @@ public void onOpen(WebSocket ws, ClientHandshake handshake) {
wsData.setWebsocket(ws);
ws.setAttachment(wsData);
JsonObject jHandshake = WebsocketUtils.handshakeToJsonObject(handshake);
- CompletableFuture.runAsync(new OnOpenHandler(AbstractWebsocketServer.this, ws, jHandshake));
+ AbstractWebsocketServer.this.execute(new OnOpenHandler(AbstractWebsocketServer.this, ws, jHandshake));
}
@Override
@@ -62,17 +63,17 @@ public void onMessage(WebSocket ws, String stringMessage) {
}
if (message instanceof JsonrpcRequest) {
- CompletableFuture.runAsync(new OnRequestHandler(AbstractWebsocketServer.this, ws,
+ AbstractWebsocketServer.this.execute(new OnRequestHandler(AbstractWebsocketServer.this, ws,
(JsonrpcRequest) message, (response) -> {
AbstractWebsocketServer.this.sendMessage(ws, response);
}));
} else if (message instanceof JsonrpcResponse) {
- CompletableFuture.runAsync(
+ AbstractWebsocketServer.this.execute(
new OnResponseHandler(AbstractWebsocketServer.this, ws, (JsonrpcResponse) message));
} else if (message instanceof JsonrpcNotification) {
- CompletableFuture.runAsync(new OnNotificationHandler(AbstractWebsocketServer.this, ws,
+ AbstractWebsocketServer.this.execute(new OnNotificationHandler(AbstractWebsocketServer.this, ws,
(JsonrpcNotification) message));
}
@@ -86,13 +87,14 @@ public void onError(WebSocket ws, Exception ex) {
if (ws == null) {
AbstractWebsocketServer.this.handleInternalErrorAsync(ex);
} else {
- CompletableFuture.runAsync(new OnErrorHandler(AbstractWebsocketServer.this, ws, ex));
+ AbstractWebsocketServer.this.execute(new OnErrorHandler(AbstractWebsocketServer.this, ws, ex));
}
}
@Override
public void onClose(WebSocket ws, int code, String reason, boolean remote) {
- CompletableFuture.runAsync(new OnCloseHandler(AbstractWebsocketServer.this, ws, code, reason, remote));
+ AbstractWebsocketServer.this
+ .execute(new OnCloseHandler(AbstractWebsocketServer.this, ws, code, reason, remote));
}
};
// Allow the port to be reused. See
@@ -136,10 +138,21 @@ public void broadcastMessage(JsonrpcMessage message) {
}
}
+ /**
+ * Gets the port number that this server listens on.
+ *
+ * @return The port number.
+ */
+ public int getPort() {
+ return this.ws.getPort();
+ }
+
/**
* Starts the websocket server
*/
+ @Override
public void start() {
+ super.start();
this.log.info("Starting [" + this.getName() + "] websocket server [port=" + this.port + "]");
this.ws.start();
}
@@ -147,6 +160,7 @@ public void start() {
/**
* Stops the websocket server
*/
+ @Override
public void stop() {
int tries = 3;
while (tries-- > 0) {
@@ -164,6 +178,7 @@ public void stop() {
}
}
this.log.error("Stopping websocket server [" + this.getName() + "] failed too often.");
+ super.stop();
}
/**
diff --git a/io.openems.common/src/io/openems/common/websocket/ClientReconnectorWorker.java b/io.openems.common/src/io/openems/common/websocket/ClientReconnectorWorker.java
index f87f6202ff7..55c68f4b806 100644
--- a/io.openems.common/src/io/openems/common/websocket/ClientReconnectorWorker.java
+++ b/io.openems.common/src/io/openems/common/websocket/ClientReconnectorWorker.java
@@ -1,7 +1,7 @@
package io.openems.common.websocket;
import java.time.Duration;
-import java.time.LocalDateTime;
+import java.time.Instant;
import java.util.Random;
import org.java_websocket.client.WebSocketClient;
@@ -13,15 +13,15 @@
public class ClientReconnectorWorker extends AbstractWorker {
- private final static int MAX_WAIT_TIME_SECONDS = 120;
- private final static int MIN_WAIT_TIME_SECONDS = 10;
+ private final static int MAX_WAIT_SECONDS = 120;
+ private final static int MIN_WAIT_SECONDS = 10;
- private final static Duration MIN_WAIT_TIME_BETWEEN_RETRIES = Duration
- .ofSeconds(new Random().nextInt(MAX_WAIT_TIME_SECONDS) + MIN_WAIT_TIME_SECONDS);
+ private final static long MIN_WAIT_SEONDCS_BETWEEN_RETRIES = new Random().nextInt(MAX_WAIT_SECONDS)
+ + MIN_WAIT_SECONDS;
private final Logger log = LoggerFactory.getLogger(ClientReconnectorWorker.class);
private final AbstractWebsocketClient> parent;
- private LocalDateTime lastTry = LocalDateTime.MIN;
+ private Instant lastTry = null;;
public ClientReconnectorWorker(AbstractWebsocketClient> parent) {
this.parent = parent;
@@ -38,14 +38,20 @@ protected void forever() throws InterruptedException {
return;
}
- Duration notWaitedEnough = Duration.between(LocalDateTime.now().minus(MIN_WAIT_TIME_BETWEEN_RETRIES),
- this.lastTry);
- if (!notWaitedEnough.isNegative()) {
- this.parent.logInfo(this.log,
- "Waiting till next WebSocket reconnect [" + notWaitedEnough.getSeconds() + "s]");
+ Instant now = Instant.now();
+
+ if (this.lastTry == null) {
+ this.lastTry = now;
+ return;
+ }
+
+ long waitedSeconds = Duration.between(this.lastTry, now).getSeconds();
+ if (waitedSeconds < MIN_WAIT_SEONDCS_BETWEEN_RETRIES) {
+ this.parent.logInfo(this.log, "Waiting till next WebSocket reconnect ["
+ + (MIN_WAIT_SEONDCS_BETWEEN_RETRIES - waitedSeconds) + "s]");
return;
}
- this.lastTry = LocalDateTime.now();
+ this.lastTry = now;
this.parent.logInfo(this.log, "Reconnecting WebSocket...");
ws.reconnectBlocking();
diff --git a/io.openems.common/src/io/openems/common/websocket/DummyWebsocketServer.java b/io.openems.common/src/io/openems/common/websocket/DummyWebsocketServer.java
new file mode 100644
index 00000000000..bd9f7945cd0
--- /dev/null
+++ b/io.openems.common/src/io/openems/common/websocket/DummyWebsocketServer.java
@@ -0,0 +1,163 @@
+package io.openems.common.websocket;
+
+import org.java_websocket.server.WebSocketServer;
+import org.slf4j.Logger;
+
+import io.openems.common.exceptions.NotImplementedException;
+
+public class DummyWebsocketServer extends AbstractWebsocketServer implements AutoCloseable {
+
+ private static class DummyWsData extends WsData {
+
+ @Override
+ public String toString() {
+ return "DummyWsData[]";
+ }
+
+ }
+
+ public static class Builder {
+ private OnOpen onOpen = (ws, handshake) -> {
+ };
+ private OnRequest onRequest = (ws, request) -> {
+ throw new NotImplementedException("On-Request handler is not implemented");
+ };
+ private OnNotification onNotification = (ws, notification) -> {
+ };
+ private OnError onError = (ws, ex) -> {
+ };
+ private OnClose onClose = (ws, code, reason, remote) -> {
+ };
+
+ private Builder() {
+ }
+
+ public DummyWebsocketServer.Builder onOpen(OnOpen onOpen) {
+ this.onOpen = onOpen;
+ return this;
+ }
+
+ public DummyWebsocketServer.Builder onRequest(OnRequest onRequest) {
+ this.onRequest = onRequest;
+ return this;
+ }
+
+ public DummyWebsocketServer.Builder onNotification(OnNotification onNotification) {
+ this.onNotification = onNotification;
+ return this;
+ }
+
+ public DummyWebsocketServer.Builder onError(OnError onError) {
+ this.onError = onError;
+ return this;
+ }
+
+ public DummyWebsocketServer.Builder onClose(OnClose onClose) {
+ this.onClose = onClose;
+ return this;
+ }
+
+ public DummyWebsocketServer build() {
+ return new DummyWebsocketServer(this);
+ }
+ }
+
+ /**
+ * Create a Config builder.
+ *
+ * @return a {@link Builder}
+ */
+ public static DummyWebsocketServer.Builder create() {
+ return new Builder();
+ }
+
+ private final DummyWebsocketServer.Builder builder;
+
+ private DummyWebsocketServer(DummyWebsocketServer.Builder builder) {
+ super("DummyWebsocketServer", 0 /* auto-select port */, 1 /* pool size */, false);
+ this.builder = builder;
+ }
+
+ @Override
+ protected WsData createWsData() {
+ return new DummyWsData();
+ }
+
+ @Override
+ protected OnOpen getOnOpen() {
+ return this.builder.onOpen;
+ }
+
+ public void withOnOpen(OnOpen onOpen) {
+ this.builder.onOpen = onOpen;
+ }
+
+ @Override
+ protected OnRequest getOnRequest() {
+ return this.builder.onRequest;
+ }
+
+ public void withOnRequest(OnRequest onRequest) {
+ this.builder.onRequest = onRequest;
+ }
+
+ @Override
+ protected OnNotification getOnNotification() {
+ return this.builder.onNotification;
+ }
+
+ public void withOnNotification(OnNotification onNotification) {
+ this.builder.onNotification = onNotification;
+ }
+
+ @Override
+ protected OnError getOnError() {
+ return this.builder.onError;
+ }
+
+ public void withOnError(OnError onError) {
+ this.builder.onError = onError;
+ }
+
+ @Override
+ protected OnClose getOnClose() {
+ return this.builder.onClose;
+ }
+
+ public void withOnClose(OnClose onClose) {
+ this.builder.onClose = onClose;
+ }
+
+ @Override
+ protected void logInfo(Logger log, String message) {
+ log.info(message);
+ }
+
+ @Override
+ protected void logWarn(Logger log, String message) {
+ log.info(message);
+ }
+
+ /**
+ * Starts the {@link WebSocketServer} and waits.
+ *
+ * @return the dynamically assigned Port.
+ * @throws InterruptedException on error
+ */
+ public int startBlocking() throws InterruptedException {
+ this.start();
+
+ // block until Port is not anymore zero
+ int port;
+ do {
+ Thread.sleep(500);
+ port = this.getPort();
+ } while (port == 0);
+ return port;
+ }
+
+ @Override
+ public void close() throws Exception {
+ this.stop();
+ }
+}
diff --git a/io.openems.common/src/io/openems/common/websocket/OnRequestHandler.java b/io.openems.common/src/io/openems/common/websocket/OnRequestHandler.java
index 3a2ddc4e494..24fcf65b37d 100644
--- a/io.openems.common/src/io/openems/common/websocket/OnRequestHandler.java
+++ b/io.openems.common/src/io/openems/common/websocket/OnRequestHandler.java
@@ -2,6 +2,8 @@
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import org.java_websocket.WebSocket;
@@ -38,14 +40,22 @@ public final void run() {
CompletableFuture extends JsonrpcResponseSuccess> responseFuture = this.parent.getOnRequest().run(this.ws,
this.request);
// Get success response
- response = responseFuture.get();
+ if (this.request.getTimeout().isPresent() && this.request.getTimeout().get() > 0) {
+ // ...with timeout
+ response = responseFuture.get(this.request.getTimeout().get(), TimeUnit.SECONDS);
+ } else {
+ // ...without timeout
+ response = responseFuture.get();
+ }
} catch (OpenemsNamedException e) {
// Get Named Exception error response
this.parent.logWarn(this.log, "JSON-RPC Error Response: " + e.getMessage());
response = new JsonrpcResponseError(request.getId(), e);
- } catch (ExecutionException | InterruptedException e) {
+ } catch (ExecutionException | InterruptedException | TimeoutException e) {
// Get GENERIC error response
- this.parent.logWarn(this.log, "JSON-RPC Error Response: " + e.getMessage());
+ this.parent.logWarn(this.log, "JSON-RPC Error Response. " + e.getClass().getSimpleName() + ". " //
+ + "Request: " + this.request.toString() + ". " //
+ + "Message: " + e.getMessage());
response = new JsonrpcResponseError(request.getId(), e.getMessage());
}
diff --git a/io.openems.common/test/io/openems/common/jsonrpc/base/GenericJsonrpcRequestTest.java b/io.openems.common/test/io/openems/common/jsonrpc/base/GenericJsonrpcRequestTest.java
new file mode 100644
index 00000000000..31111f054cc
--- /dev/null
+++ b/io.openems.common/test/io/openems/common/jsonrpc/base/GenericJsonrpcRequestTest.java
@@ -0,0 +1,45 @@
+package io.openems.common.jsonrpc.base;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Optional;
+import java.util.UUID;
+
+import org.junit.Test;
+
+import com.google.gson.JsonObject;
+
+import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
+import io.openems.common.utils.JsonUtils;
+
+public class GenericJsonrpcRequestTest {
+
+ @Test
+ public void test() throws OpenemsNamedException {
+ UUID id = UUID.randomUUID();
+ String method = "dummyMethod";
+ JsonObject params = JsonUtils.buildJsonObject() //
+ .addProperty("hello", "world") //
+ .addProperty("foo", "bar") //
+ .build();
+ int timeout = 10;
+
+ // Test toString()
+ GenericJsonrpcRequest sut = new GenericJsonrpcRequest(id, method, params, timeout);
+ String json = sut.toString();
+
+ assertEquals(
+ "{\"jsonrpc\":\"2.0\",\"method\":\"dummyMethod\",\"params\":{\"hello\":\"world\",\"foo\":\"bar\"},\"id\":\""
+ + id.toString() + "\",\"timeout\":10}",
+ json);
+
+ // Test from()
+ sut = GenericJsonrpcRequest.from(json);
+ assertEquals(id, sut.getId());
+ assertEquals(method, sut.getMethod());
+ assertEquals(Optional.of(timeout), sut.getTimeout());
+ assertEquals("{\"hello\":\"world\",\"foo\":\"bar\"}", sut.getParams().toString());
+
+ }
+
+}
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 c5d379cc6ec..7a406830559 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,12 +3,11 @@
import org.osgi.annotation.versioning.ProviderType;
import io.openems.common.channel.AccessMode;
-import io.openems.common.channel.Level;
+import io.openems.common.channel.PersistencePriority;
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;
@@ -34,6 +33,7 @@
public interface Battery extends StartStoppable, OpenemsComponent {
public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
+
/**
* State of Charge.
*
@@ -45,7 +45,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
SOC(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.PERCENT)),
+ .unit(Unit.PERCENT) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* State of Health.
@@ -58,7 +59,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
SOH(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.PERCENT)),
+ .unit(Unit.PERCENT) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Voltage of battery.
@@ -70,7 +72,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.VOLT)),
+ .unit(Unit.VOLT) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Current of battery.
@@ -82,7 +85,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
CURRENT(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE)),
+ .unit(Unit.AMPERE) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Capacity of battery.
@@ -94,7 +98,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
CAPACITY(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT_HOURS)),
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Maximal voltage for charging.
@@ -106,7 +111,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
CHARGE_MAX_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.VOLT)),
+ .unit(Unit.VOLT) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Maximum current for charging.
@@ -119,7 +125,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
CHARGE_MAX_CURRENT(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE)),
+ .unit(Unit.AMPERE) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Minimal voltage for discharging.
@@ -131,7 +138,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
DISCHARGE_MIN_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.VOLT)),
+ .unit(Unit.VOLT) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Maximum current for discharging.
@@ -144,7 +152,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
DISCHARGE_MAX_CURRENT(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE)),
+ .unit(Unit.AMPERE) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Minimal Cell Temperature.
@@ -156,7 +165,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
MIN_CELL_TEMPERATURE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.DEGREE_CELSIUS)),
+ .unit(Unit.DEGREE_CELSIUS) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Maximum Cell Temperature.
@@ -169,7 +179,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
MAX_CELL_TEMPERATURE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.DEGREE_CELSIUS)),
+ .unit(Unit.DEGREE_CELSIUS) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Minimal cell voltage.
@@ -193,31 +204,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
MAX_CELL_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT)),
-
- // TODO FORCE_CHARGE_ACTIVE and FORCE_DISCHARGE_ACTIVE channels are
- // deprecated/obsolete by BatteryProtection channels
- /**
- * Force charge active.
- *
- *
- * - Interface: Battery
- *
- Indicates that battery is in force charge mode
- *
- */
- FORCE_CHARGE_ACTIVE(Doc.of(Level.INFO).text("Force charge mode is active")), //
-
- /**
- * Force discharge active.
- *
- *
- * - Interface: Battery
- *
- Indicates that battery is in force discharge mode
- *
- */
- FORCE_DISCHARGE_ACTIVE(Doc.of(Level.INFO).text("Force discharge mode is active")), //
-
- ;
+ .unit(Unit.MILLIVOLT) //
+ .persistencePriority(PersistencePriority.HIGH));
private final Doc doc;
@@ -744,81 +732,4 @@ 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/api/CellCharacteristic.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/api/CellCharacteristic.java
deleted file mode 100644
index 5829decbaaf..00000000000
--- a/io.openems.edge.battery.api/src/io/openems/edge/battery/api/CellCharacteristic.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package io.openems.edge.battery.api;
-
-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.api/src/io/openems/edge/battery/api/SetAllowedCurrents.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/api/SetAllowedCurrents.java
deleted file mode 100644
index b4e0de68c53..00000000000
--- a/io.openems.edge.battery.api/src/io/openems/edge/battery/api/SetAllowedCurrents.java
+++ /dev/null
@@ -1,192 +0,0 @@
-package io.openems.edge.battery.api;
-
-import io.openems.edge.common.channel.IntegerReadChannel;
-
-public class SetAllowedCurrents {
-
- private int lastMaxChargeCurrentFromBmsMilliAmpere = 0;
- private int lastMaxDischargeCurrentFromBmsMilliAmpere = 0;
-
- private Battery battery;
- private CellCharacteristic cellCharacteristic;
- private Settings settings;
- private IntegerReadChannel maxChargeCurrentChannel;
- private IntegerReadChannel maxDischargeCurrentChannel;
-
- public SetAllowedCurrents(//
- Battery battery, //
- CellCharacteristic cellCharacteristic, //
- Settings settings, //
- IntegerReadChannel maxChargeCurrentChannel, //
- IntegerReadChannel maxDischargeCurrentChannel //
- ) {
- super();
- this.battery = battery;
- this.cellCharacteristic = cellCharacteristic;
- this.settings = settings;
- this.maxChargeCurrentChannel = maxChargeCurrentChannel;
- this.maxDischargeCurrentChannel = maxDischargeCurrentChannel;
- }
-
- /**
- * Calculates the allowed currents.
- */
- public void act() {
-
- int maxChargeCurrentFromBmsMilliAmpere = this.maxChargeCurrentChannel.value().orElse(0);
-
- // limit increasing
- if (maxChargeCurrentFromBmsMilliAmpere > this.lastMaxChargeCurrentFromBmsMilliAmpere + this.settings.getMaxIncreaseMilliAmpere()) {
- maxChargeCurrentFromBmsMilliAmpere = this.lastMaxChargeCurrentFromBmsMilliAmpere + this.settings.getMaxIncreaseMilliAmpere();
- }
- this.lastMaxChargeCurrentFromBmsMilliAmpere = maxChargeCurrentFromBmsMilliAmpere;
-
- int maxDischargeCurrentFromBmsMilliAmpere = this.maxDischargeCurrentChannel.value().orElse(0);
-
- // limit increasing
- if (maxDischargeCurrentFromBmsMilliAmpere > this.lastMaxDischargeCurrentFromBmsMilliAmpere + this.settings.getMaxIncreaseMilliAmpere()) {
- maxDischargeCurrentFromBmsMilliAmpere = this.lastMaxDischargeCurrentFromBmsMilliAmpere + this.settings.getMaxIncreaseMilliAmpere();
- }
- this.lastMaxDischargeCurrentFromBmsMilliAmpere = maxDischargeCurrentFromBmsMilliAmpere;
-
- setMaxAllowedCurrents(this.battery, this.cellCharacteristic, this.settings, maxChargeCurrentFromBmsMilliAmpere / 1000,
- maxDischargeCurrentFromBmsMilliAmpere / 1000);
-
- }
-
- /**
- * Sets the MaxAllowedCurrents.
- * @param battery the {@link Battery}
- * @param cellCharacteristic the {@link CellCharacteristic}
- * @param settings the {@link Settings}
- * @param maxChargeCurrentFromBms int
- * @param maxDischargeCurrentFromBms int
- */
- public static void setMaxAllowedCurrents(//
- Battery battery, //
- CellCharacteristic cellCharacteristic, //
- Settings settings, //
- int maxChargeCurrentFromBms, //
- int maxDischargeCurrentFromBms //
- ) {
-
- int maxChargeCurrent = maxChargeCurrentFromBms;
- int maxDischargeCurrent = maxDischargeCurrentFromBms;
-
- if (!areApiValuesPresent(battery)) {
- maxChargeCurrent = 0;
- maxDischargeCurrent = 0;
- } else {
- if (isChargingAlready(battery)) {
- if (isFurtherChargingNecessary(battery, cellCharacteristic,settings)) {
- maxDischargeCurrent = calculateForceDischargeCurrent(battery, settings);
- }
- } else {
- if (isVoltageBelowFinalDischargingVoltage(cellCharacteristic, battery)) {
- if (isVoltageHigherThanForceChargeVoltage(cellCharacteristic, battery)) {
- maxDischargeCurrent = 0;
- } else {
- maxDischargeCurrent = calculateForceDischargeCurrent(battery, settings);
- }
- }
- }
-
- if (isDischargingAlready(battery)) {
- if (isFurtherDischargingNecessary(cellCharacteristic, battery)) {
- maxChargeCurrent = calculateForceChargeCurrent(battery, settings);
- }
- } else {
- if (isVoltageAboveFinalChargingVoltage(cellCharacteristic, battery)) {
- if (isVoltageLowerThanForceDischargeVoltage(cellCharacteristic, battery)) {
- maxChargeCurrent = 0;
- } else {
- maxChargeCurrent = calculateForceChargeCurrent(battery, settings);
- }
- }
- }
- }
-
- 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);
- }
-
- protected static boolean isVoltageLowerThanForceDischargeVoltage(CellCharacteristic cellCharacteristic,
- Battery battery) {
- return battery.getMaxCellVoltage().get() < cellCharacteristic.getForceDischargeCellVoltage_mV();
- }
-
- protected static boolean isVoltageAboveFinalChargingVoltage(CellCharacteristic cellCharacteristic,
- Battery battery) {
- return battery.getMaxCellVoltage().get() > 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, Settings settings) {
- return calculateForceCurrent(battery, settings);
- }
-
- protected static int calculateForceChargeCurrent(Battery battery, Settings settings) {
- return calculateForceCurrent(battery, settings);
- }
-
- protected static int calculateForceCurrent(Battery battery, Settings settings) {
- double capacity = battery.getCapacity().get();
- double voltage = battery.getVoltage().get();
- double power = capacity * settings.getPowerFactor();//POWER_FACTOR;
- double current = power / voltage;
- int value = -(int) Math.max(settings.getMinimumCurrentAmpere(), current);//MINIMUM_CURRENT_AMPERE, current);
- return value;
- }
-
- protected static boolean isFurtherChargingNecessary(Battery battery, CellCharacteristic cellCharacteristic, Settings settings) {
- if (!battery.getForceChargeActive().isDefined()) {
- return false;
- }
- return battery.getForceChargeActive().get()
- && battery.getMinCellVoltage().get() < (cellCharacteristic.getFinalCellDischargeVoltage_mV() - settings.getToleranceMilliVolt());
- }
-
- 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.api/src/io/openems/edge/battery/api/Settings.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Settings.java
deleted file mode 100644
index 001eab1681a..00000000000
--- a/io.openems.edge.battery.api/src/io/openems/edge/battery/api/Settings.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package io.openems.edge.battery.api;
-
-public interface Settings {
-
- /**
- * Gets the max increase in milli ampere.
- * @return int
- */
- int getMaxIncreaseMilliAmpere();
-
- /**
- * Gets the power factor.
- * @return double
- */
- double getPowerFactor();
-
- /**
- * Gets the minimal current in ampere.
- * @return double
- */
- double getMinimumCurrentAmpere();
-
- /**
- * Gets the tolerance in millivolt.
- * @return int
- */
- int getToleranceMilliVolt();
-
-}
\ No newline at end of file
diff --git a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtection.java b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtection.java
index b87af843273..5689735a788 100644
--- a/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtection.java
+++ b/io.openems.edge.battery.api/src/io/openems/edge/battery/protection/BatteryProtection.java
@@ -1,5 +1,6 @@
package io.openems.edge.battery.protection;
+import io.openems.common.channel.PersistencePriority;
import io.openems.common.channel.Unit;
import io.openems.common.types.OpenemsType;
import io.openems.edge.battery.api.Battery;
@@ -39,7 +40,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
BP_CHARGE_BMS(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE)),
+ .unit(Unit.AMPERE) //
+ .persistencePriority(PersistencePriority.MEDIUM)), //
/**
* Discharge Current limit provided by the Battery/BMS.
*
@@ -50,7 +52,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
BP_DISCHARGE_BMS(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE)),
+ .unit(Unit.AMPERE) //
+ .persistencePriority(PersistencePriority.MEDIUM)), //
/**
* Charge Current limit derived from Min-Cell-Voltage.
*
@@ -61,7 +64,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
BP_CHARGE_MIN_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE)),
+ .unit(Unit.AMPERE) //
+ .persistencePriority(PersistencePriority.MEDIUM)), //
/**
* Discharge Current limit derived from Min-Cell-Voltage.
*
@@ -72,7 +76,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
BP_DISCHARGE_MIN_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE)),
+ .unit(Unit.AMPERE) //
+ .persistencePriority(PersistencePriority.MEDIUM)), //
/**
* Charge Current limit derived from Max-Cell-Voltage.
*
@@ -83,7 +88,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
BP_CHARGE_MAX_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE)),
+ .unit(Unit.AMPERE) //
+ .persistencePriority(PersistencePriority.MEDIUM)), //
/**
* Discharge Current limit derived from Max-Cell-Voltage.
*
@@ -94,7 +100,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
BP_DISCHARGE_MAX_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE)),
+ .unit(Unit.AMPERE) //
+ .persistencePriority(PersistencePriority.MEDIUM)), //
/**
* Charge Current limit derived from Min-Cell-Temperature.
*
@@ -105,7 +112,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
BP_CHARGE_MIN_TEMPERATURE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE)),
+ .unit(Unit.AMPERE) //
+ .persistencePriority(PersistencePriority.MEDIUM)), //
/**
* Discharge Current limit derived from Min-Cell-Temperature.
*
@@ -116,7 +124,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
BP_DISCHARGE_MIN_TEMPERATURE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE)),
+ .unit(Unit.AMPERE) //
+ .persistencePriority(PersistencePriority.MEDIUM)), //
/**
* Charge Current limit derived from Max-Cell-Temperature.
*
@@ -127,7 +136,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
BP_CHARGE_MAX_TEMPERATURE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE)),
+ .unit(Unit.AMPERE) //
+ .persistencePriority(PersistencePriority.MEDIUM)), //
/**
* Discharge Current limit derived from Max-Cell-Temperature.
*
@@ -138,7 +148,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
BP_DISCHARGE_MAX_TEMPERATURE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE)),
+ .unit(Unit.AMPERE) //
+ .persistencePriority(PersistencePriority.MEDIUM)), //
/**
* Charge Max-Increase Current limit.
*
@@ -149,7 +160,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
BP_CHARGE_INCREASE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE)),
+ .unit(Unit.AMPERE) //
+ .persistencePriority(PersistencePriority.MEDIUM)), //
/**
* Discharge Max-Increase Current limit.
*
@@ -160,7 +172,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
BP_DISCHARGE_INCREASE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE)),
+ .unit(Unit.AMPERE) //
+ .persistencePriority(PersistencePriority.MEDIUM)), //
/**
* Force-Discharge State.
*
@@ -170,7 +183,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
* Unit: Ampere
*
*/
- BP_FORCE_DISCHARGE(Doc.of(AbstractForceChargeDischarge.State.values())), //
+ BP_FORCE_DISCHARGE(Doc.of(AbstractForceChargeDischarge.State.values()) //
+ .persistencePriority(PersistencePriority.MEDIUM)), //
/**
* Force-Charge State.
*
@@ -180,7 +194,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
* Unit: Ampere
*
*/
- BP_FORCE_CHARGE(Doc.of(AbstractForceChargeDischarge.State.values())) //
+ BP_FORCE_CHARGE(Doc.of(AbstractForceChargeDischarge.State.values()) //
+ .persistencePriority(PersistencePriority.MEDIUM)), //
;
private final Doc doc;
diff --git a/io.openems.edge.battery.api/test/io/openems/edge/battery/api/DummyBattery.java b/io.openems.edge.battery.api/test/io/openems/edge/battery/api/DummyBattery.java
deleted file mode 100644
index 952b486dfb9..00000000000
--- a/io.openems.edge.battery.api/test/io/openems/edge/battery/api/DummyBattery.java
+++ /dev/null
@@ -1,157 +0,0 @@
-package io.openems.edge.battery.api;
-
-import io.openems.common.exceptions.NotImplementedException;
-import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
-import io.openems.edge.common.component.AbstractOpenemsComponent;
-import io.openems.edge.common.component.OpenemsComponent;
-import io.openems.edge.common.startstop.StartStop;
-import io.openems.edge.common.startstop.StartStoppable;
-
-// TODO merge with io.openems.edge.battery.test.DummyBattery
-public class DummyBattery extends AbstractOpenemsComponent implements Battery, StartStoppable {
-
- 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(//
- ) { //
- super(//
- OpenemsComponent.ChannelId.values(), //
- Battery.ChannelId.values(), //
- StartStoppable.ChannelId.values() //
- );
-
- this.setMinimalCellVoltage(DEFAULT_MIN_CELL_VOLTAGE);
- this.setMaximalCellVoltage(DEFAULT_MAX_CELL_VOLTAGE);
- this.setMinimalCellTemperature(DEFAULT_MIN_CELL_TEMPERATURE);
- this.setMaximalCellTemperature(DEFAULT_MAX_CELL_TEMPERATURE);
- this.setSoc(DEFAULT_SOC);
- this.setCapacity(DEFAULT_CAPACITY);
- this.setVoltage(DEFAULT_VOLTAGE);
- this.setChargeMaxCurrent(DEFAULT_MAX_CHARGE_CURRENT);
- this.setDischargeMaxCurrent(DEFAULT_MAX_DISCHARGE_CURRENT);
- }
-
- void setMinimalCellVoltage(int minimalCellVoltage) {
- this._setMinCellVoltage(minimalCellVoltage);
- this.getMinCellVoltageChannel().nextProcessImage();
- }
-
- void setMinimalCellVoltageToUndefined() {
- this._setMinCellVoltage(null);
- this.getMinCellVoltageChannel().nextProcessImage();
- }
-
- void setMaximalCellVoltage(int maximalCellVoltage) {
- this._setMaxCellVoltage(maximalCellVoltage);
- this.getMaxCellVoltageChannel().nextProcessImage();
- }
-
- void setMaximalCellVoltageToUndefined() {
- this._setMaxCellVoltage(null);
- this.getMaxCellVoltageChannel().nextProcessImage();
- }
-
- void setMinimalCellTemperature(int minimalCellTemperature) {
- this._setMinCellTemperature(minimalCellTemperature);
- this.getMinCellTemperatureChannel().nextProcessImage();
- }
-
- void setMinimalCellTemperatureToUndefined() {
- this._setMinCellTemperature(null);
- this.getMinCellTemperatureChannel().nextProcessImage();
- }
-
- void setMaximalCellTemperature(int maximalCellTemperature) {
- this._setMaxCellTemperature(maximalCellTemperature);
- this.getMaxCellTemperatureChannel().nextProcessImage();
- }
-
- void setMaximalCellTemperatureToUndefined() {
- this._setMaxCellTemperature(null);
- this.getMaxCellTemperatureChannel().nextProcessImage();
- }
-
- void setSoc(int soc) {
- this._setSoc(soc);
- this.getSocChannel().nextProcessImage();
- }
-
- void setSocToUndefined() {
- this._setSoc(null);
- this.getSocChannel().nextProcessImage();
- }
-
- void setVoltage(int voltage) {
- this._setVoltage(voltage);
- this.getVoltageChannel().nextProcessImage();
- }
-
- void setVoltageToUndefined() {
- this._setVoltage(null);
- this.getVoltageChannel().nextProcessImage();
- }
-
- void setCapacity(int capacity) {
- this._setCapacity(capacity);
- this.getCapacityChannel().nextProcessImage();
- }
-
- void setCapacityToUndefined() {
- this._setCapacity(null);
- this.getCapacityChannel().nextProcessImage();
- }
-
- void setForceDischargeActive(boolean active) {
- this._setForceDischargeActive(active);
- this.getForceDischargeActiveChannel().nextProcessImage();
- }
-
- void setForceDischargeActiveToUndefined() {
- this._setForceDischargeActive(null);
- this.getForceDischargeActiveChannel().nextProcessImage();
- }
-
- void setForceChargeActive(boolean active) {
- this._setForceChargeActive(active);
- this.getForceChargeActiveChannel().nextProcessImage();
- }
-
- void setForceChargeActiveToUndefined() {
- this._setForceChargeActive(null);
- this.getForceChargeActiveChannel().nextProcessImage();
- }
-
- void setChargeMaxCurrent(int value) {
- this._setChargeMaxCurrent(value);
- this.getChargeMaxCurrentChannel().nextProcessImage();
- }
-
- void setChargeMaxCurrentToUndefined() {
- this._setChargeMaxCurrent(null);
- this.getChargeMaxCurrentChannel().nextProcessImage();
- }
-
- void setDischargeMaxCurrent(int value) {
- this._setDischargeMaxCurrent(value);
- this.getDischargeMaxCurrentChannel().nextProcessImage();
- }
-
- 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");
- }
-}
diff --git a/io.openems.edge.battery.api/test/io/openems/edge/battery/api/DummyCellCharacteristic.java b/io.openems.edge.battery.api/test/io/openems/edge/battery/api/DummyCellCharacteristic.java
deleted file mode 100644
index 51bc4507f46..00000000000
--- a/io.openems.edge.battery.api/test/io/openems/edge/battery/api/DummyCellCharacteristic.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package io.openems.edge.battery.api;
-
-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.api/test/io/openems/edge/battery/api/SetAllowedCurrentsTest.java b/io.openems.edge.battery.api/test/io/openems/edge/battery/api/SetAllowedCurrentsTest.java
deleted file mode 100644
index d6c38051c10..00000000000
--- a/io.openems.edge.battery.api/test/io/openems/edge/battery/api/SetAllowedCurrentsTest.java
+++ /dev/null
@@ -1,469 +0,0 @@
-package io.openems.edge.battery.api;
-
-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 SetAllowedCurrentsTest {
-
- private DummyBattery battery;
- private DummyCellCharacteristic cellCharacteristic;
- private Settings settings;
-
- private static int MAX_INCREASE_MILLI_AMPERE = 300;
- private static double MIN_CURRENT_AMPERE = 1;
- private static int TOLERANCE_MILLI_VOLT = 10;
- private static double POWER_FACTOR = 0.02;
-
- @Before
- public void setUp() throws Exception {
- this.battery = new DummyBattery();
- this.cellCharacteristic = new DummyCellCharacteristic();
- this.settings = new SettingsImpl(TOLERANCE_MILLI_VOLT, MIN_CURRENT_AMPERE, POWER_FACTOR,
- MAX_INCREASE_MILLI_AMPERE);
- }
-
- @Test
- public void testBatteryIsChargedUntilFinalDischargeIsReached() {
- // Battery has to be charged
- int maxDischargeCurrentFromBms = 0;
- int maxChargeCurrentFromBms = DummyBattery.DEFAULT_MAX_CHARGE_CURRENT;
- this.battery.setMinimalCellVoltage(DummyCellCharacteristic.FORCE_CHARGE_CELL_VOLTAGE_MV);
-
- SetAllowedCurrents.setMaxAllowedCurrents(this.battery, this.cellCharacteristic, this.settings,
- maxChargeCurrentFromBms, maxDischargeCurrentFromBms);
-
- this.battery.getChargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceDischargeActiveChannel().nextProcessImage();
- this.battery.getDischargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceChargeActiveChannel().nextProcessImage();
-
- int expectedMaxChargeCurrent = maxChargeCurrentFromBms;
- int actualMaxChargeCurrent = this.battery.getChargeMaxCurrent().get();
- assertEquals(expectedMaxChargeCurrent, actualMaxChargeCurrent);
-
- int expectedMaxDischargeCurrent = -(int) Math.max(MIN_CURRENT_AMPERE,
- this.battery.getCapacity().get() * POWER_FACTOR / this.battery.getVoltage().get());
- int actualMaxDischargeCurrent = this.battery.getDischargeMaxCurrent().get();
- assertEquals(expectedMaxDischargeCurrent, actualMaxDischargeCurrent);
-
- boolean expectedChargeForce = true;
- boolean actualChargeForce = this.battery.getForceChargeActive().get();
- assertEquals(expectedChargeForce, actualChargeForce);
-
- boolean expectedDischargeForce = false;
- boolean actualdischargeForce = this.battery.getForceDischargeActive().get();
- assertEquals(expectedDischargeForce, actualdischargeForce);
-
- // Min Voltage has risen above force level, but is still under final discharge
- // level minus tolerance
- this.battery.setMinimalCellVoltage(
- DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV - this.settings.getToleranceMilliVolt() - 1);
- SetAllowedCurrents.setMaxAllowedCurrents(this.battery, this.cellCharacteristic, this.settings,
- maxChargeCurrentFromBms, maxDischargeCurrentFromBms);
-
- this.battery.getChargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceDischargeActiveChannel().nextProcessImage();
- this.battery.getDischargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceChargeActiveChannel().nextProcessImage();
-
- expectedMaxChargeCurrent = maxChargeCurrentFromBms;
- actualMaxChargeCurrent = this.battery.getChargeMaxCurrent().get();
- assertEquals(expectedMaxChargeCurrent, actualMaxChargeCurrent);
-
- expectedMaxDischargeCurrent = -(int) Math.max(MIN_CURRENT_AMPERE,
- this.battery.getCapacity().get() * POWER_FACTOR / this.battery.getVoltage().get());
- actualMaxDischargeCurrent = this.battery.getDischargeMaxCurrent().get();
- assertEquals(expectedMaxDischargeCurrent, actualMaxDischargeCurrent);
-
- expectedChargeForce = true;
- actualChargeForce = this.battery.getForceChargeActive().get();
- assertEquals(expectedChargeForce, actualChargeForce);
-
- expectedDischargeForce = false;
- actualdischargeForce = this.battery.getForceDischargeActive().get();
- assertEquals(expectedDischargeForce, actualdischargeForce);
-
- // Min Voltage has risen above final discharge level
- this.battery.setMinimalCellVoltage(DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV + 1);
- SetAllowedCurrents.setMaxAllowedCurrents(this.battery, this.cellCharacteristic, this.settings,
- maxChargeCurrentFromBms, maxDischargeCurrentFromBms);
-
- this.battery.getChargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceDischargeActiveChannel().nextProcessImage();
- this.battery.getDischargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceChargeActiveChannel().nextProcessImage();
-
- expectedMaxChargeCurrent = maxChargeCurrentFromBms;
- actualMaxChargeCurrent = this.battery.getChargeMaxCurrent().get();
- assertEquals(expectedMaxChargeCurrent, actualMaxChargeCurrent);
-
- expectedMaxDischargeCurrent = maxDischargeCurrentFromBms;
- actualMaxDischargeCurrent = this.battery.getDischargeMaxCurrent().get();
- assertEquals(expectedMaxDischargeCurrent, actualMaxDischargeCurrent);
-
- expectedChargeForce = false;
- actualChargeForce = this.battery.getForceChargeActive().get();
- assertEquals(expectedChargeForce, actualChargeForce);
-
- expectedDischargeForce = false;
- actualdischargeForce = this.battery.getForceDischargeActive().get();
- assertEquals(expectedDischargeForce, actualdischargeForce);
- }
-
- @Test
- public void testSetMaxAllowedCurrents() {
- // Nothing is necessary
- int maxDischargeCurrentFromBms = DummyBattery.DEFAULT_MAX_DISCHARGE_CURRENT;
- int maxChargeCurrentFromBms = DummyBattery.DEFAULT_MAX_CHARGE_CURRENT;
- SetAllowedCurrents.setMaxAllowedCurrents(this.battery, this.cellCharacteristic, this.settings,
- maxChargeCurrentFromBms, maxDischargeCurrentFromBms);
-
- this.battery.getChargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceDischargeActiveChannel().nextProcessImage();
- this.battery.getDischargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceChargeActiveChannel().nextProcessImage();
-
- int expectedMaxChargeCurrent = maxChargeCurrentFromBms;
- int actualMaxChargeCurrent = this.battery.getChargeMaxCurrent().get();
- assertEquals(expectedMaxChargeCurrent, actualMaxChargeCurrent);
- int expectedMaxDischargeCurrent = maxDischargeCurrentFromBms;
- int actualMaxDischargeCurrent = this.battery.getDischargeMaxCurrent().get();
- assertEquals(expectedMaxDischargeCurrent, actualMaxDischargeCurrent);
- boolean expectedChargeForce = false;
- boolean actualChargeForce = this.battery.getForceChargeActive().get();
- assertEquals(expectedChargeForce, actualChargeForce);
- boolean expectedDischargeForce = false;
- boolean actualdischargeForce = this.battery.getForceDischargeActive().get();
- assertEquals(expectedDischargeForce, actualdischargeForce);
-
- // Battery has to be charged
- maxDischargeCurrentFromBms = 0;
- this.battery.setMinimalCellVoltage(DummyCellCharacteristic.FORCE_CHARGE_CELL_VOLTAGE_MV);
-
- SetAllowedCurrents.setMaxAllowedCurrents(this.battery, this.cellCharacteristic, this.settings,
- maxChargeCurrentFromBms, maxDischargeCurrentFromBms);
-
- this.battery.getChargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceDischargeActiveChannel().nextProcessImage();
- this.battery.getDischargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceChargeActiveChannel().nextProcessImage();
-
- expectedMaxChargeCurrent = maxChargeCurrentFromBms;
- actualMaxChargeCurrent = this.battery.getChargeMaxCurrent().get();
- assertEquals(expectedMaxChargeCurrent, actualMaxChargeCurrent);
-
- expectedMaxDischargeCurrent = -(int) Math.max(MIN_CURRENT_AMPERE,
- this.battery.getCapacity().get() * POWER_FACTOR / this.battery.getVoltage().get());
- actualMaxDischargeCurrent = this.battery.getDischargeMaxCurrent().get();
- assertEquals(expectedMaxDischargeCurrent, actualMaxDischargeCurrent);
- expectedChargeForce = true;
- actualChargeForce = this.battery.getForceChargeActive().get();
- assertEquals(expectedChargeForce, actualChargeForce);
- expectedDischargeForce = false;
- actualdischargeForce = this.battery.getForceDischargeActive().get();
- assertEquals(expectedDischargeForce, actualdischargeForce);
- }
-
- @Test
- public void testSetChannelsForCharge() {
- int expectedCurrent = DummyBattery.DEFAULT_MAX_CHARGE_CURRENT;
- int actualCurrent = this.battery.getChargeMaxCurrent().get();
- assertEquals(expectedCurrent, actualCurrent);
-
- // Battery can be charged, no discharge necessary
- int maxChargeCurrent = DummyBattery.DEFAULT_MAX_CHARGE_CURRENT + 1;
- SetAllowedCurrents.setChannelsForCharge(maxChargeCurrent, this.battery);
- this.battery.getChargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceDischargeActiveChannel().nextProcessImage();
-
- expectedCurrent = maxChargeCurrent;
- actualCurrent = this.battery.getChargeMaxCurrent().get();
- assertEquals(expectedCurrent, actualCurrent);
-
- boolean expectedForce = false;
- boolean actualForce = this.battery.getForceDischargeActive().get();
- assertEquals(expectedForce, actualForce);
-
- // Battery cannot be charged, no discharge necessary
- maxChargeCurrent = 0;
- SetAllowedCurrents.setChannelsForCharge(maxChargeCurrent, this.battery);
- this.battery.getChargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceDischargeActiveChannel().nextProcessImage();
-
- expectedCurrent = maxChargeCurrent;
- actualCurrent = this.battery.getChargeMaxCurrent().get();
- assertEquals(expectedCurrent, actualCurrent);
-
- expectedForce = false;
- actualForce = this.battery.getForceDischargeActive().get();
- assertEquals(expectedForce, actualForce);
-
- // Battery cannot be charged, must be discharged
- maxChargeCurrent = -8;
- SetAllowedCurrents.setChannelsForCharge(maxChargeCurrent, this.battery);
- this.battery.getChargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceDischargeActiveChannel().nextProcessImage();
-
- expectedCurrent = maxChargeCurrent;
- actualCurrent = this.battery.getChargeMaxCurrent().get();
- assertEquals(expectedCurrent, actualCurrent);
-
- expectedForce = true;
- actualForce = this.battery.getForceDischargeActive().get();
- assertEquals(expectedForce, actualForce);
- }
-
- @Test
- public void testSetChannelsForDischarge() {
- int expectedCurrent = DummyBattery.DEFAULT_MAX_DISCHARGE_CURRENT;
- int actualCurrent = this.battery.getDischargeMaxCurrent().get();
- assertEquals(expectedCurrent, actualCurrent);
-
- // Battery can be discharged, no charge necessary
- int maxDischargeCurrent = DummyBattery.DEFAULT_MAX_DISCHARGE_CURRENT + 1;
- SetAllowedCurrents.setChannelsForDischarge(maxDischargeCurrent, this.battery);
- this.battery.getDischargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceChargeActiveChannel().nextProcessImage();
-
- expectedCurrent = maxDischargeCurrent;
- actualCurrent = this.battery.getDischargeMaxCurrent().get();
- assertEquals(expectedCurrent, actualCurrent);
-
- boolean expectedForce = false;
- boolean actualForce = this.battery.getForceChargeActive().get();
- assertEquals(expectedForce, actualForce);
-
- // Battery cannot be discharged, no charge necessary
- maxDischargeCurrent = 0;
- SetAllowedCurrents.setChannelsForDischarge(maxDischargeCurrent, this.battery);
- this.battery.getDischargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceChargeActiveChannel().nextProcessImage();
-
- expectedCurrent = maxDischargeCurrent;
- actualCurrent = this.battery.getDischargeMaxCurrent().get();
- assertEquals(expectedCurrent, actualCurrent);
-
- expectedForce = false;
- actualForce = this.battery.getForceChargeActive().get();
- assertEquals(expectedForce, actualForce);
-
- // Battery cannot be charged, must be charged
- maxDischargeCurrent = -8;
- SetAllowedCurrents.setChannelsForDischarge(maxDischargeCurrent, this.battery);
- this.battery.getDischargeMaxCurrentChannel().nextProcessImage();
- this.battery.getForceChargeActiveChannel().nextProcessImage();
-
- expectedCurrent = maxDischargeCurrent;
- actualCurrent = this.battery.getDischargeMaxCurrent().get();
- assertEquals(expectedCurrent, actualCurrent);
-
- expectedForce = true;
- actualForce = this.battery.getForceChargeActive().get();
- assertEquals(expectedForce, actualForce);
- }
-
- @Test
- public void testIsVoltageLowerThanForceDischargeVoltage() {
-
- assertTrue(SetAllowedCurrents.isVoltageLowerThanForceDischargeVoltage(this.cellCharacteristic, this.battery));
-
- this.battery.setMaximalCellVoltage((DummyCellCharacteristic.FORCE_DISCHARGE_CELL_VOLTAGE_MV - 1));
- assertTrue(SetAllowedCurrents.isVoltageLowerThanForceDischargeVoltage(this.cellCharacteristic, this.battery));
-
- this.battery.setMaximalCellVoltage((DummyCellCharacteristic.FORCE_DISCHARGE_CELL_VOLTAGE_MV));
- assertFalse(SetAllowedCurrents.isVoltageLowerThanForceDischargeVoltage(this.cellCharacteristic, this.battery));
-
- this.battery.setMaximalCellVoltage((DummyCellCharacteristic.FORCE_DISCHARGE_CELL_VOLTAGE_MV + 1));
- assertFalse(SetAllowedCurrents.isVoltageLowerThanForceDischargeVoltage(this.cellCharacteristic, this.battery));
- }
-
- @Test
- public void testIsVoltageAboveFinalChargingVoltage() {
- assertFalse(SetAllowedCurrents.isVoltageAboveFinalChargingVoltage(this.cellCharacteristic, this.battery));
-
- this.battery.setMaximalCellVoltage((DummyCellCharacteristic.FINAL_CELL_CHARGE_VOLTAGE_MV - 1));
- assertFalse(SetAllowedCurrents.isVoltageAboveFinalChargingVoltage(this.cellCharacteristic, this.battery));
-
- this.battery.setMaximalCellVoltage((DummyCellCharacteristic.FINAL_CELL_CHARGE_VOLTAGE_MV));
- assertFalse(SetAllowedCurrents.isVoltageAboveFinalChargingVoltage(this.cellCharacteristic, this.battery));
-
- this.battery.setMaximalCellVoltage((DummyCellCharacteristic.FINAL_CELL_CHARGE_VOLTAGE_MV + 1));
- assertTrue(SetAllowedCurrents.isVoltageAboveFinalChargingVoltage(this.cellCharacteristic, this.battery));
- }
-
- @Test
- public void testIsVoltageHigherThanForceChargeVoltage() {
- assertTrue(SetAllowedCurrents.isVoltageHigherThanForceChargeVoltage(this.cellCharacteristic, this.battery));
-
- this.battery.setMinimalCellVoltage((DummyCellCharacteristic.FORCE_CHARGE_CELL_VOLTAGE_MV - 1));
- assertFalse(SetAllowedCurrents.isVoltageHigherThanForceChargeVoltage(this.cellCharacteristic, this.battery));
-
- this.battery.setMinimalCellVoltage((DummyCellCharacteristic.FORCE_CHARGE_CELL_VOLTAGE_MV));
- assertFalse(SetAllowedCurrents.isVoltageHigherThanForceChargeVoltage(this.cellCharacteristic, this.battery));
-
- this.battery.setMinimalCellVoltage((DummyCellCharacteristic.FORCE_CHARGE_CELL_VOLTAGE_MV + 1));
- assertTrue(SetAllowedCurrents.isVoltageHigherThanForceChargeVoltage(this.cellCharacteristic, this.battery));
- }
-
- @Test
- public void testIsVoltageBelowFinalDischargingVoltage() {
- assertFalse(SetAllowedCurrents.isVoltageBelowFinalDischargingVoltage(this.cellCharacteristic, this.battery));
-
- this.battery.setMinimalCellVoltage(DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV - 1);
- assertTrue(SetAllowedCurrents.isVoltageBelowFinalDischargingVoltage(this.cellCharacteristic, this.battery));
-
- this.battery.setMinimalCellVoltage((DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV));
- assertFalse(SetAllowedCurrents.isVoltageBelowFinalDischargingVoltage(this.cellCharacteristic, this.battery));
-
- this.battery.setMinimalCellVoltage((DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV + 1));
- assertFalse(SetAllowedCurrents.isVoltageBelowFinalDischargingVoltage(this.cellCharacteristic, this.battery));
- }
-
- @Test
- public void testIsFurtherDischargingNecessary() {
- assertFalse(SetAllowedCurrents.isFurtherDischargingNecessary(this.cellCharacteristic, this.battery));
-
- this.battery.setMaximalCellVoltage(DummyCellCharacteristic.FINAL_CELL_CHARGE_VOLTAGE_MV + 1);
- assertFalse(SetAllowedCurrents.isFurtherDischargingNecessary(this.cellCharacteristic, this.battery));
-
- this.battery.setMaximalCellVoltage(DummyCellCharacteristic.FORCE_DISCHARGE_CELL_VOLTAGE_MV + 1);
- assertFalse(SetAllowedCurrents.isFurtherDischargingNecessary(this.cellCharacteristic, this.battery));
-
- this.battery.setForceDischargeActive(false);
- assertFalse(SetAllowedCurrents.isFurtherDischargingNecessary(this.cellCharacteristic, this.battery));
-
- this.battery.setForceDischargeActive(true);
- assertTrue(SetAllowedCurrents.isFurtherDischargingNecessary(this.cellCharacteristic, this.battery));
-
- this.battery.setMaximalCellVoltage(DummyCellCharacteristic.FINAL_CELL_CHARGE_VOLTAGE_MV + 1);
- assertTrue(SetAllowedCurrents.isFurtherDischargingNecessary(this.cellCharacteristic, this.battery));
-
- this.battery.setMaximalCellVoltage(DummyCellCharacteristic.FINAL_CELL_CHARGE_VOLTAGE_MV);
- assertFalse(SetAllowedCurrents.isFurtherDischargingNecessary(this.cellCharacteristic, this.battery));
- }
-
- @Test
- public void testIsDischargingAlready() {
- assertFalse(SetAllowedCurrents.isDischargingAlready(this.battery));
-
- this.battery.setForceDischargeActive(true);
- assertTrue(SetAllowedCurrents.isDischargingAlready(this.battery));
-
- this.battery.setForceDischargeActive(false);
- assertFalse(SetAllowedCurrents.isDischargingAlready(this.battery));
- }
-
- @Test
- public void testCalculateForceCurrent() {
- int expected = -(int) Math.max(MIN_CURRENT_AMPERE,
- DummyBattery.DEFAULT_CAPACITY * POWER_FACTOR / DummyBattery.DEFAULT_VOLTAGE); // 1.333 => 1
- assertEquals(expected, SetAllowedCurrents.calculateForceCurrent(this.battery, this.settings));
-
- int newCapacity = 200_000;
- this.battery.setCapacity(newCapacity);
- // 5.333 => 5
- expected = -(int) Math.max(MIN_CURRENT_AMPERE, newCapacity * POWER_FACTOR / DummyBattery.DEFAULT_VOLTAGE);
- assertEquals(expected, SetAllowedCurrents.calculateForceCurrent(this.battery, this.settings));
-
- int newVoltage = 850;
- this.battery.setCapacity(newCapacity);
- this.battery.setVoltage(newVoltage);
- expected = -(int) Math.max(MIN_CURRENT_AMPERE, newCapacity * POWER_FACTOR / newVoltage); // 4.706 => 4
- assertEquals(expected, SetAllowedCurrents.calculateForceCurrent(this.battery, this.settings));
-
- newCapacity = 30_000;
- newVoltage = 700;
- this.battery.setCapacity(newCapacity);
- this.battery.setVoltage(newVoltage);
- expected = -(int) Math.max(MIN_CURRENT_AMPERE, newCapacity * POWER_FACTOR / newVoltage); // 0.857 => 1
- assertEquals(expected, SetAllowedCurrents.calculateForceCurrent(this.battery, this.settings));
-
- newCapacity = 10_000;
- this.battery.setCapacity(newCapacity);
- this.battery.setVoltage(newVoltage);
- expected = -(int) Math.max(MIN_CURRENT_AMPERE, newCapacity * POWER_FACTOR / newVoltage); // 0.286 => 1
- assertEquals(expected, SetAllowedCurrents.calculateForceCurrent(this.battery, this.settings));
- }
-
- @Test
- public void testCalculateForceDischargeCurrent() {
- int expected = -(int) Math.max(MIN_CURRENT_AMPERE,
- DummyBattery.DEFAULT_CAPACITY * POWER_FACTOR / DummyBattery.DEFAULT_VOLTAGE); // 1.333 => 1
- assertEquals(expected, SetAllowedCurrents.calculateForceDischargeCurrent(this.battery, this.settings));
- }
-
- @Test
- public void testCalculateForceChargeCurrent() {
- int expected = -(int) Math.max(MIN_CURRENT_AMPERE,
- DummyBattery.DEFAULT_CAPACITY * POWER_FACTOR / DummyBattery.DEFAULT_VOLTAGE); // 1.333 => 1
- assertEquals(expected, SetAllowedCurrents.calculateForceDischargeCurrent(this.battery, this.settings));
- }
-
- @Test
- public void testIsFurtherChargingNecessary() {
- assertFalse(
- SetAllowedCurrents.isFurtherChargingNecessary(this.battery, this.cellCharacteristic, this.settings));
-
- this.battery.setMinimalCellVoltage(DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV - 1);
- assertFalse(
- SetAllowedCurrents.isFurtherChargingNecessary(this.battery, this.cellCharacteristic, this.settings));
-
- this.battery.setMinimalCellVoltage(DummyCellCharacteristic.FORCE_CHARGE_CELL_VOLTAGE_MV - 1);
- assertFalse(
- SetAllowedCurrents.isFurtherChargingNecessary(this.battery, this.cellCharacteristic, this.settings));
-
- this.battery.setForceChargeActive(false);
- assertFalse(
- SetAllowedCurrents.isFurtherChargingNecessary(this.battery, this.cellCharacteristic, this.settings));
-
- this.battery.setForceChargeActive(true);
- assertTrue(SetAllowedCurrents.isFurtherChargingNecessary(this.battery, this.cellCharacteristic, this.settings));
-
- this.battery.setMinimalCellVoltage(
- DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV - this.settings.getToleranceMilliVolt() - 1);
- assertTrue(SetAllowedCurrents.isFurtherChargingNecessary(this.battery, this.cellCharacteristic, this.settings));
-
- this.battery.setMinimalCellVoltage(
- DummyCellCharacteristic.FINAL_CELL_DISCHARGE_VOLTAGE_MV - this.settings.getToleranceMilliVolt());
- assertFalse(
- SetAllowedCurrents.isFurtherChargingNecessary(this.battery, this.cellCharacteristic, this.settings));
- }
-
- @Test
- public void testIsChargingAlready() {
- assertFalse(SetAllowedCurrents.isChargingAlready(this.battery));
-
- this.battery.setForceChargeActive(true);
- assertTrue(SetAllowedCurrents.isChargingAlready(this.battery));
-
- this.battery.setForceChargeActive(false);
- assertFalse(SetAllowedCurrents.isChargingAlready(this.battery));
- }
-
- @Test
- public void testAreApiValuesPresent() {
- assertTrue(SetAllowedCurrents.areApiValuesPresent(this.battery));
-
- this.battery.setCapacityToUndefined();
- assertFalse(SetAllowedCurrents.areApiValuesPresent(this.battery));
-
- this.battery.setCapacity(DummyBattery.DEFAULT_CAPACITY);
- this.battery.setVoltageToUndefined();
- assertFalse(SetAllowedCurrents.areApiValuesPresent(this.battery));
-
- this.battery.setVoltage(DummyBattery.DEFAULT_VOLTAGE);
- this.battery.setMinimalCellVoltageToUndefined();
- assertFalse(SetAllowedCurrents.areApiValuesPresent(this.battery));
-
- this.battery.setMinimalCellVoltage(DummyBattery.DEFAULT_MIN_CELL_VOLTAGE);
- this.battery.setMaximalCellVoltageToUndefined();
- assertFalse(SetAllowedCurrents.areApiValuesPresent(this.battery));
-
- this.battery.setMaximalCellVoltage(DummyBattery.DEFAULT_MAX_CELL_VOLTAGE);
- assertTrue(SetAllowedCurrents.areApiValuesPresent(this.battery));
- }
-}
\ No newline at end of file
diff --git a/io.openems.edge.battery.api/test/io/openems/edge/battery/api/SettingsImpl.java b/io.openems.edge.battery.api/test/io/openems/edge/battery/api/SettingsImpl.java
deleted file mode 100644
index b6ec52ae835..00000000000
--- a/io.openems.edge.battery.api/test/io/openems/edge/battery/api/SettingsImpl.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package io.openems.edge.battery.api;
-
-public class SettingsImpl implements Settings {
-
- private int toleranceMilliVolt;
- private double minimumCurrentAmpere;
- private double powerFactor;
- private int maxIncreaseMilliAmpere;
-
- public SettingsImpl(int toleranceMilliVolt, double minimumCurrentAmpere, double powerFactor,
- int maxIncreaseMilliAmpere) {
- super();
- this.toleranceMilliVolt = toleranceMilliVolt;
- this.minimumCurrentAmpere = minimumCurrentAmpere;
- this.powerFactor = powerFactor;
- this.maxIncreaseMilliAmpere = maxIncreaseMilliAmpere;
- }
-
- @Override
- public int getMaxIncreaseMilliAmpere() {
- return this.maxIncreaseMilliAmpere;
- }
-
- @Override
- public double getPowerFactor() {
- return this.powerFactor;
- }
-
- @Override
- public double getMinimumCurrentAmpere() {
- return this.minimumCurrentAmpere;
- }
-
- @Override
- public int getToleranceMilliVolt() {
- return this.toleranceMilliVolt;
- }
-
-}
diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BatteryBoxC130.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BatteryBoxC130.java
index acde6cce71f..f80ac6bb55c 100644
--- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BatteryBoxC130.java
+++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BatteryBoxC130.java
@@ -162,10 +162,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
.unit(Unit.MILLIVOLT)), //
SYSTEM_INSULATION(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.KILOOHM)), //
- SYSTEM_ACCEPT_MAX_CHARGE_CURRENT(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIAMPERE)), //
- SYSTEM_ACCEPT_MAX_DISCHARGE_CURRENT(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIAMPERE)), //
CLUSTER_1_BATTERY_000_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.MILLIVOLT)), //
CLUSTER_1_BATTERY_001_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BatteryBoxC130Impl.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BatteryBoxC130Impl.java
index a972015817f..10868f73131 100644
--- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BatteryBoxC130Impl.java
+++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BatteryBoxC130Impl.java
@@ -24,10 +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.api.SetAllowedCurrents;
import io.openems.edge.battery.bydcommercial.statemachine.Context;
import io.openems.edge.battery.bydcommercial.statemachine.StateMachine;
import io.openems.edge.battery.bydcommercial.statemachine.StateMachine.State;
+import io.openems.edge.battery.protection.BatteryProtection;
import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent;
import io.openems.edge.bridge.modbus.api.BridgeModbus;
import io.openems.edge.bridge.modbus.api.ElementToChannelConverter;
@@ -38,6 +38,7 @@
import io.openems.edge.bridge.modbus.api.element.UnsignedWordElement;
import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask;
import io.openems.edge.bridge.modbus.api.task.FC6WriteRegisterTask;
+import io.openems.edge.common.component.ComponentManager;
import io.openems.edge.common.component.OpenemsComponent;
import io.openems.edge.common.event.EdgeEventConstants;
import io.openems.edge.common.modbusslave.ModbusSlave;
@@ -52,8 +53,8 @@
immediate = true, //
configurationPolicy = ConfigurationPolicy.REQUIRE, //
property = { //
- EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, //
- EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE //
+ EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, //
+ EventConstants.EVENT_TOPIC + "=" + EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE //
})
public class BatteryBoxC130Impl extends AbstractOpenemsModbusComponent
implements BatteryBoxC130, Battery, OpenemsComponent, EventHandler, ModbusSlave, StartStoppable {
@@ -70,29 +71,25 @@ public class BatteryBoxC130Impl extends AbstractOpenemsModbusComponent
@Reference
protected ConfigurationAdmin cm;
+ @Reference
+ protected ComponentManager componentManager;
+
/**
* Manages the {@link State}s of the StateMachine.
*/
private final StateMachine stateMachine = new StateMachine(State.UNDEFINED);
private Config config;
- private SetAllowedCurrents setAllowedCurrents;
+ private BatteryProtection batteryProtection = null;
public BatteryBoxC130Impl() {
super(//
OpenemsComponent.ChannelId.values(), //
Battery.ChannelId.values(), //
StartStoppable.ChannelId.values(), //
- BatteryBoxC130.ChannelId.values() //
+ BatteryBoxC130.ChannelId.values(), //
+ BatteryProtection.ChannelId.values() //
);
-
- this.setAllowedCurrents = new SetAllowedCurrents(//
- this, //
- new BydC130CellCharacteristic(), //
- new SingleRackSettings(), //
- this.channel(BatteryBoxC130.ChannelId.SYSTEM_ACCEPT_MAX_CHARGE_CURRENT), //
- this.channel(BatteryBoxC130.ChannelId.SYSTEM_ACCEPT_MAX_DISCHARGE_CURRENT) //
- );
}
@Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY)
@@ -108,6 +105,11 @@ void activate(ComponentContext context, Config config) throws OpenemsNamedExcept
return;
}
+ // Initialize Battery-Protection
+ this.batteryProtection = BatteryProtection.create(this) //
+ .applyBatteryProtectionDefinition(new BatteryProtectionDefinitionBydC130(), this.componentManager) //
+ .build();
+
int maxVoltage = this.config.numberOfSlaves() * MAX_ALLOWED_VOLTAGE_PER_MODULE;
_setChargeMaxVoltage(maxVoltage);
@@ -131,11 +133,9 @@ public void handleEvent(Event event) {
switch (event.getTopic()) {
case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE:
-
- this.setAllowedCurrents.act();
-
+ this.batteryProtection.apply();
break;
-
+
case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE:
this.handleStateMachine();
break;
@@ -318,10 +318,10 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
), //
new FC3ReadRegistersTask(0x216C, Priority.HIGH, //
- m(BatteryBoxC130.ChannelId.SYSTEM_ACCEPT_MAX_CHARGE_CURRENT, new SignedWordElement(0x216C), //
- ElementToChannelConverter.SCALE_FACTOR_2), //
- m(BatteryBoxC130.ChannelId.SYSTEM_ACCEPT_MAX_DISCHARGE_CURRENT, new SignedWordElement(0x216D), //
- ElementToChannelConverter.SCALE_FACTOR_2) //
+ m(BatteryProtection.ChannelId.BP_CHARGE_BMS, new UnsignedWordElement(0x216C),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
+ m(BatteryProtection.ChannelId.BP_DISCHARGE_BMS, new UnsignedWordElement(0x216D),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1) //
), //
new FC3ReadRegistersTask(0x2183, Priority.LOW, //
@@ -682,7 +682,7 @@ public StartStop getStartStopTarget() {
/*
* Handle incompatibility with old hardware protocol.
*
- * 'onRegister0x2100Update()' callback is called when register 0x2100 is read.
+ * 'onRegister0x2100Update()' callback is called when register 0x2100 is read.
*/
private boolean isModbusProtocolInitialized = false;
diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BatteryProtectionDefinitionBydC130.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BatteryProtectionDefinitionBydC130.java
new file mode 100644
index 00000000000..8af87ce25bc
--- /dev/null
+++ b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BatteryProtectionDefinitionBydC130.java
@@ -0,0 +1,83 @@
+package io.openems.edge.battery.bydcommercial;
+
+import io.openems.edge.battery.protection.BatteryProtectionDefinition;
+import io.openems.edge.battery.protection.force.ForceCharge;
+import io.openems.edge.battery.protection.force.ForceDischarge;
+import io.openems.edge.common.linecharacteristic.PolyLine;
+
+public class BatteryProtectionDefinitionBydC130 implements BatteryProtectionDefinition {
+
+ @Override
+ public int getInitialBmsMaxEverChargeCurrent() {
+ return 80; // [A]
+ }
+
+ @Override
+ public int getInitialBmsMaxEverDischargeCurrent() {
+ return 80; // [A]
+ }
+
+ @Override
+ public PolyLine getChargeVoltageToPercent() {
+ return PolyLine.create() //
+ .addPoint(3000, 0.1) //
+ .addPoint(Math.nextUp(3000), 1) //
+ .addPoint(3350, 1) //
+ .addPoint(3450, 0.9999) //
+ .addPoint(3600, 0.02) //
+ .addPoint(Math.nextDown(3650), 0.02) //
+ .addPoint(3650, 0) //
+ .build();
+ }
+
+ @Override
+ public PolyLine getDischargeVoltageToPercent() {
+ return PolyLine.create() //
+ .addPoint(2900, 0) //
+ .addPoint(Math.nextUp(2900), 0.01) //
+ .addPoint(2920, 0.01) //
+ .addPoint(3000, 1) //
+ .addPoint(3700, 1) //
+ .addPoint(Math.nextUp(3700), 0) //
+ .build();
+ }
+
+ @Override
+ public PolyLine getChargeTemperatureToPercent() {
+ return PolyLine.create() //
+ .addPoint(0, 0) //
+ .addPoint(Math.nextUp(0), 0.01) //
+ .addPoint(18, 1) //
+ .addPoint(35, 1) //
+ .addPoint(Math.nextDown(40), 0.01) //
+ .addPoint(40, 0) //
+ .build();
+ }
+
+ @Override
+ public PolyLine getDischargeTemperatureToPercent() {
+ return PolyLine.create() //
+ .addPoint(0, 0) //
+ .addPoint(Math.nextUp(0), 0.01) //
+ .addPoint(12, 1) //
+ .addPoint(45, 1) //
+ .addPoint(Math.nextDown(55), 0.01) //
+ .addPoint(55, 0) //
+ .build();
+ }
+
+ @Override
+ public ForceDischarge.Params getForceDischargeParams() {
+ return new ForceDischarge.Params(3660, 3640, 3450);
+ }
+
+ @Override
+ public ForceCharge.Params getForceChargeParams() {
+ return new ForceCharge.Params(2850, 2910, 3000);
+ }
+
+ @Override
+ public Double getMaxIncreaseAmperePerSecond() {
+ return 0.1; // [A] per second
+ }
+}
\ No newline at end of file
diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BydC130CellCharacteristic.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BydC130CellCharacteristic.java
deleted file mode 100644
index 132dedcbbc0..00000000000
--- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/BydC130CellCharacteristic.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package io.openems.edge.battery.bydcommercial;
-
-import io.openems.edge.battery.api.CellCharacteristic;
-
-public class BydC130CellCharacteristic implements CellCharacteristic {
-
- @Override
- public int getFinalCellDischargeVoltage_mV() {
- return 2_900;
- }
-
- @Override
- public int getForceChargeCellVoltage_mV() {
- return 2_850;
- }
-
- @Override
- public int getFinalCellChargeVoltage_mV() {
- return 3_650;
- }
-
- @Override
- public int getForceDischargeCellVoltage_mV() {
- return 3_680;
- }
-
-}
\ No newline at end of file
diff --git a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/SingleRackSettings.java b/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/SingleRackSettings.java
deleted file mode 100644
index 869fd44da87..00000000000
--- a/io.openems.edge.battery.bydcommercial/src/io/openems/edge/battery/bydcommercial/SingleRackSettings.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package io.openems.edge.battery.bydcommercial;
-
-import io.openems.edge.battery.api.Settings;
-
-public class SingleRackSettings implements Settings {
-
- private static final double POWER_FACTOR = 0.02;
- private static final int MINIMUM_CURRENT_AMPERE = 1;
- private static final int TOLERANCE_MILLI_VOLT = 10;
- private static final int MAX_INCREASE_MILLIAMPERE = 300;
-
- @Override
- public int getMaxIncreaseMilliAmpere() {
- return MAX_INCREASE_MILLIAMPERE;
- }
-
- @Override
- public double getPowerFactor() {
- return POWER_FACTOR;
- }
-
- @Override
- public double getMinimumCurrentAmpere() {
- return MINIMUM_CURRENT_AMPERE;
- }
-
- @Override
- public int getToleranceMilliVolt() {
- return TOLERANCE_MILLI_VOLT;
- }
-
-}
diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/ChannelIdImpl.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/ChannelIdImpl.java
new file mode 100644
index 00000000000..641276b596d
--- /dev/null
+++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/ChannelIdImpl.java
@@ -0,0 +1,29 @@
+package io.openems.edge.battery.fenecon.home;
+
+import io.openems.edge.common.channel.ChannelId;
+import io.openems.edge.common.channel.Doc;
+
+/**
+ * This class is used to create Cell Voltage and Temperature Dynamic Channels.
+ */
+public class ChannelIdImpl implements ChannelId {
+ ;
+
+ private final String name;
+ private final Doc doc;
+
+ public ChannelIdImpl(String name, Doc doc) {
+ this.name = name;
+ this.doc = doc;
+ }
+
+ @Override
+ public String name() {
+ return this.name;
+ }
+
+ @Override
+ public Doc doc() {
+ return this.doc;
+ }
+}
diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBattery.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBattery.java
index ae67b95e7d8..23cb716f4db 100644
--- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBattery.java
+++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBattery.java
@@ -3,13 +3,12 @@
import io.openems.common.channel.AccessMode;
import io.openems.common.channel.Level;
import io.openems.common.channel.Unit;
-import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.common.types.OpenemsType;
import io.openems.edge.battery.api.Battery;
import io.openems.edge.battery.fenecon.home.enums.BmsControl;
-import io.openems.edge.battery.fenecon.home.enums.State;
+import io.openems.edge.battery.fenecon.home.statemachine.StateMachine.State;
+import io.openems.edge.common.channel.Channel;
import io.openems.edge.common.channel.Doc;
-import io.openems.edge.common.channel.WriteChannel;
import io.openems.edge.common.channel.value.Value;
import io.openems.edge.common.component.OpenemsComponent;
import io.openems.edge.common.startstop.StartStop;
@@ -22,7 +21,7 @@ public interface FeneconHomeBattery extends Battery, OpenemsComponent, StartStop
*
* @return the Channel
*/
- public default WriteChannel getBmsControlChannel() {
+ public default Channel getBmsControlChannel() {
return this.channel(ChannelId.BMS_CONTROL);
}
@@ -45,16 +44,6 @@ public default void _setBmsControl(BmsControl value) {
this.getBmsControlChannel().setNextValue(value);
}
- /**
- * Writes the value to the {@link ChannelId#BMS_CONTROL} Register.
- *
- * @param value the next value
- * @throws OpenemsNamedException on error
- */
- public default void setBmsControl(BmsControl value) throws OpenemsNamedException {
- this.getBmsControlChannel().setNextWriteValue(value);
- }
-
/**
* Gets the target Start/Stop mode from config or StartStop-Channel.
*
@@ -64,793 +53,636 @@ public default void setBmsControl(BmsControl value) throws OpenemsNamedException
public static enum ChannelId implements io.openems.edge.common.channel.ChannelId {
// EnumWriteChannels
- RACK_PRE_ALARM_CELL_OVER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_PRE_ALARM_CELL_OVER_VOLTAGE(Doc.of(Level.INFO) //
.text("Rack Cell Over Voltage Alarm")), //
- RACK_PRE_ALARM_CELL_UNDER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_PRE_ALARM_CELL_UNDER_VOLTAGE(Doc.of(Level.INFO) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Cell Under Voltage Alarm")), //
- RACK_PRE_ALARM_OVER_CHARGING_CURRENT(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_PRE_ALARM_OVER_CHARGING_CURRENT(Doc.of(Level.INFO) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Over Charging Current Alarm")), //
- RACK_PRE_ALARM_OVER_DISCHARGING_CURRENT(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_PRE_ALARM_OVER_DISCHARGING_CURRENT(Doc.of(Level.INFO) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Over Discharging Current Alarm")), //
- RACK_PRE_ALARM_OVER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_PRE_ALARM_OVER_TEMPERATURE(Doc.of(Level.INFO) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Over Temperature Alarm")), //
- RACK_PRE_ALARM_UNDER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_PRE_ALARM_UNDER_TEMPERATURE(Doc.of(Level.INFO) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Under Temperature Alarm")), //
- RACK_PRE_ALARM_CELL_VOLTAGE_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_PRE_ALARM_CELL_VOLTAGE_DIFFERENCE(Doc.of(Level.INFO) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Cell VOltage Difference Alarm")), //
- RACK_PRE_ALARM_BCU_TEMP_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_PRE_ALARM_BCU_TEMP_DIFFERENCE(Doc.of(Level.INFO) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack BCU Temp Difference Alarm")), //
- RACK_PRE_ALARM_UNDER_SOC(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_PRE_ALARM_UNDER_SOC(Doc.of(Level.INFO) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Under SOC Alarm")), //
- RACK_PRE_ALARM_UNDER_SOH(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_PRE_ALARM_UNDER_SOH(Doc.of(Level.INFO) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Under SOH Alarm")), //
- RACK_PRE_ALARM_OVER_CHARGING_POWER(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_PRE_ALARM_OVER_CHARGING_POWER(Doc.of(Level.INFO) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Over Charging Alarm")), //
- RACK_PRE_ALARM_OVER_DISCHARGING_POWER(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_PRE_ALARM_OVER_DISCHARGING_POWER(Doc.of(Level.INFO) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Over Discharging Alarm")), //
- RACK_LEVEL_1_CELL_OVER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_1_CELL_OVER_VOLTAGE(Doc.of(Level.WARNING) //
.text("Rack Cell Over Voltage warning")), //
- RACK_LEVEL_1_CELL_UNDER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_1_CELL_UNDER_VOLTAGE(Doc.of(Level.WARNING) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Cell Under Voltage warning")), //
- RACK_LEVEL_1_OVER_CHARGING_CURRENT(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_1_OVER_CHARGING_CURRENT(Doc.of(Level.WARNING) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Over Charging Current warning")), //
- RACK_LEVEL_1_OVER_DISCHARGING_CURRENT(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_1_OVER_DISCHARGING_CURRENT(Doc.of(Level.WARNING) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Over Discharging Current warning")), //
- RACK_LEVEL_1_OVER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_1_OVER_TEMPERATURE(Doc.of(Level.WARNING) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Over Temperature warning")), //
- RACK_LEVEL_1_UNDER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_1_UNDER_TEMPERATURE(Doc.of(Level.WARNING) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Under Temperature warning")), //
- RACK_LEVEL_1_CELL_VOLTAGE_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_1_CELL_VOLTAGE_DIFFERENCE(Doc.of(Level.WARNING) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Cell VOltage Difference warning")), //
- RACK_LEVEL_1_BCU_TEMP_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_1_BCU_TEMP_DIFFERENCE(Doc.of(Level.WARNING) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack BCU Temp Difference warning")), //
- RACK_LEVEL_1_UNDER_SOC(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_1_UNDER_SOC(Doc.of(Level.WARNING) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Under SOC warning")), //
- RACK_LEVEL_1_UNDER_SOH(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_1_UNDER_SOH(Doc.of(Level.WARNING) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Under SOH warning")), //
- RACK_LEVEL_1_OVER_CHARGING_POWER(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_1_OVER_CHARGING_POWER(Doc.of(Level.WARNING) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Over Charging warning")), //
- RACK_LEVEL_1_OVER_DISCHARGING_POWER(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_1_OVER_DISCHARGING_POWER(Doc.of(Level.WARNING) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Over Discharging warning")), //
- RACK_LEVEL_2_CELL_OVER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_2_CELL_OVER_VOLTAGE(Doc.of(Level.FAULT) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Cell Over Voltage Fault")), //
- RACK_LEVEL_2_CELL_UNDER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_2_CELL_UNDER_VOLTAGE(Doc.of(Level.FAULT) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Cell Under Voltage Fault")), //
- RACK_LEVEL_2_OVER_CHARGING_CURRENT(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_2_OVER_CHARGING_CURRENT(Doc.of(Level.FAULT) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Over Charging Current Fault")), //
- RACK_LEVEL_2_OVER_DISCHARGING_CURRENT(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_2_OVER_DISCHARGING_CURRENT(Doc.of(Level.FAULT) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Over Discharging Current Fault")), //
- RACK_LEVEL_2_OVER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_2_OVER_TEMPERATURE(Doc.of(Level.FAULT) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Over Temperature Fault")), //
- RACK_LEVEL_2_UNDER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_2_UNDER_TEMPERATURE(Doc.of(Level.FAULT) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Under Temperature Fault")), //
- RACK_LEVEL_2_CELL_VOLTAGE_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_2_CELL_VOLTAGE_DIFFERENCE(Doc.of(Level.FAULT) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Cell Voltage Difference Fault")), //
- RACK_LEVEL_2_BCU_TEMP_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_2_BCU_TEMP_DIFFERENCE(Doc.of(Level.FAULT) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack BCU Temp Difference Fault")), //
- RACK_LEVEL_2_CELL_TEMPERATURE_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_2_CELL_TEMPERATURE_DIFFERENCE(Doc.of(Level.FAULT) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Cell Temperature Difference Fault")), //
- RACK_LEVEL_2_INTERNAL_COMMUNICATION(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_2_INTERNAL_COMMUNICATION(Doc.of(Level.FAULT) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Internal Communication Fault")), //
- RACK_LEVEL_2_EXTERNAL_COMMUNICATION(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_2_EXTERNAL_COMMUNICATION(Doc.of(Level.FAULT) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack External Communication Fault")), //
- RACK_LEVEL_2_PRE_CHARGE_FAIL(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_2_PRE_CHARGE_FAIL(Doc.of(Level.FAULT) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Pre Charge Fault")), //
- RACK_LEVEL_2_PARALLEL_FAIL(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_2_PARALLEL_FAIL(Doc.of(Level.FAULT) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Parallel Fault")), //
- RACK_LEVEL_2_SYSTEM_FAIL(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_2_SYSTEM_FAIL(Doc.of(Level.FAULT) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack System Fault")), //
- RACK_LEVEL_2_HARDWARE_FAIL(Doc.of(OpenemsType.BOOLEAN) //
+ RACK_LEVEL_2_HARDWARE_FAIL(Doc.of(Level.FAULT) //
.accessMode(AccessMode.READ_ONLY) //
.text("Rack Hardware Fault")), //
- ALARM_POSITION_BCU_1(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+
+ // Alarm BCU Position
+ ALARM_POSITION_BCU_1(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Alarm BCU 1 Position ")), //
- ALARM_POSITION_BCU_2(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ ALARM_POSITION_BCU_2(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Alarm BCU 2 Position ")), //
- ALARM_POSITION_BCU_3(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ ALARM_POSITION_BCU_3(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Alarm BCU 3 Position ")), //
- ALARM_POSITION_BCU_4(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ ALARM_POSITION_BCU_4(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Alarm BCU 4 Position ")), //
- ALARM_POSITION_BCU_5(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ ALARM_POSITION_BCU_5(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Alarm BCU 5 Position ")), //
- ALARM_POSITION_BCU_6(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ ALARM_POSITION_BCU_6(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Alarm BCU 6 Position ")), //
- ALARM_POSITION_BCU_7(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ ALARM_POSITION_BCU_7(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Alarm BCU 7 Position ")), //
- ALARM_POSITION_BCU_8(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ ALARM_POSITION_BCU_8(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Alarm BCU 8 Position ")), //
- ALARM_POSITION_BCU_9(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ ALARM_POSITION_BCU_9(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Alarm BCU 9 Position ")), //
- ALARM_POSITION_BCU_10(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ ALARM_POSITION_BCU_10(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Alarm BCU 10 Position ")), //
- WARNING_POSITION_BCU_1(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+
+ // Warning BCU Position
+ WARNING_POSITION_BCU_1(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Warning BCU 1 Position ")), //
- WARNING_POSITION_BCU_2(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ WARNING_POSITION_BCU_2(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Warning BCU 2 Position ")), //
- WARNING_POSITION_BCU_3(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ WARNING_POSITION_BCU_3(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Warning BCU 3 Position ")), //
- WARNING_POSITION_BCU_4(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ WARNING_POSITION_BCU_4(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Warning BCU 4 Position ")), //
- WARNING_POSITION_BCU_5(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ WARNING_POSITION_BCU_5(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Warning BCU 5 Position ")), //
- WARNING_POSITION_BCU_6(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ WARNING_POSITION_BCU_6(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Warning BCU 6 Position ")), //
- WARNING_POSITION_BCU_7(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ WARNING_POSITION_BCU_7(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Warning BCU 7 Position ")), //
- WARNING_POSITION_BCU_8(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ WARNING_POSITION_BCU_8(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Warning BCU 8 Position ")), //
- WARNING_POSITION_BCU_9(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ WARNING_POSITION_BCU_9(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Warning BCU 9 Position ")), //
- WARNING_POSITION_BCU_10(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ WARNING_POSITION_BCU_10(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Warning BCU 10 Position ")), //
- FAULT_POSITION_BCU_1(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+
+ // Fault BCU Position
+ FAULT_POSITION_BCU_1(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Fault BCU 1 Position ")), //
- FAULT_POSITION_BCU_2(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ FAULT_POSITION_BCU_2(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Fault BCU 2 Position ")), //
- FAULT_POSITION_BCU_3(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ FAULT_POSITION_BCU_3(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Fault BCU 3 Position ")), //
- FAULT_POSITION_BCU_4(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ FAULT_POSITION_BCU_4(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Fault BCU 4 Position ")), //
- FAULT_POSITION_BCU_5(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ FAULT_POSITION_BCU_5(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Fault BCU 5 Position ")), //
- FAULT_POSITION_BCU_6(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ FAULT_POSITION_BCU_6(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Fault BCU 6 Position ")), //
- FAULT_POSITION_BCU_7(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ FAULT_POSITION_BCU_7(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Fault BCU 7 Position ")), //
- FAULT_POSITION_BCU_8(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ FAULT_POSITION_BCU_8(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Fault BCU 8 Position ")), //
- FAULT_POSITION_BCU_9(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ FAULT_POSITION_BCU_9(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Fault BCU 9 Position ")), //
- FAULT_POSITION_BCU_10(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ FAULT_POSITION_BCU_10(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Fault BCU 10 Position ")), //
- BATTERY_RACK_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.VOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("Battery Rack Voltage")), //
- BATTERY_RACK_CURRENT(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("Battery Rack Current")), //
- BATTERY_RACK_SOC(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.PERCENT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("Battery Rack State Of Charge")), //
- BATTERY_RACK_SOH(Doc.of(OpenemsType.INTEGER)//
- .unit(Unit.PERCENT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("Battery Rack State Of Health")), //
- CELL_VOLTAGE_MIN(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("Min Cell Voltage of All Module")), //
+
ID_OF_CELL_VOLTAGE_MIN(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.NONE) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Id. (Min Cell Voltage)")), //
- CELL_VOLTAGE_MAX(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("Cell Voltage MAX")), //
ID_OF_CELL_VOLTAGE_MAX(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.NONE) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Id. (Max Cell Voltage)")), //
MIN_TEMPERATURE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.DEGREE_CELSIUS) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Min Temperature of Battery Rack")), //
ID_OF_MIN_TEMPERATURE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.NONE) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Id. (Min Temp)")), //
MAX_TEMPERATURE(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Max Temperature of Battery Rack")), //
ID_OF_MAX_TEMPERATURE(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Id. (Max Temp)")), //
- MAX_CHARGE_CURRENT(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("Battery Rack DC Charge Current Limit")), //
- MAX_DISCHARGE_CURRENT(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("Battery Rack DC Discharge Current Limit")),
MAX_DC_CHARGE_CURRENT_LIMIT_PER_BCU(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.AMPERE) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Max Charge Current Limit Per BCU")), //
MAX_DC_DISCHARGE_CURRENT_LIMIT_PER_BCU(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.AMPERE) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Max Discharge Current Limit Per BCU")),
RACK_NUMBER_OF_BATTERY_BCU(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.NONE) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Count Of The Connected BCU")),
RACK_NUMBER_OF_CELLS_IN_SERIES_PER_MODULE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.NONE) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack Number Of Cells in Series Per Module")),
RACK_MAX_CELL_VOLTAGE_LIMIT(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack Upper Cell Voltage Border -> System will stop charging if a cell reaches this voltage value")),
RACK_MIN_CELL_VOLTAGE_LIMIT(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack Lower Cell Voltage Border -> System will stop discharging if a cell reaches this voltage value")),
- RACK_HW_AFE_COMMUNICATION_FAULT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+
+ // Rack HW Fault Detail
+ RACK_HW_AFE_COMMUNICATION_FAULT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack HW AFE Communication Fault")),
- RACK_HW_ACTOR_DRIVER_FAULT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_HW_ACTOR_DRIVER_FAULT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack HW Actor Driver Fault")),
- RACK_HW_EEPROM_COMMUNICATION_FAULT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_HW_EEPROM_COMMUNICATION_FAULT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack HW EEPROM Communication Fault")),
- RACK_HW_VOLTAGE_DETECT_FAULT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_HW_VOLTAGE_DETECT_FAULT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack HW Voltage Detect Voltage")),
- RACK_HW_TEMPERATURE_DETECT_FAULT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_HW_TEMPERATURE_DETECT_FAULT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack HW Temperature Detect Fault")),
- RACK_HW_CURRENT_DETECT_FAULT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_HW_CURRENT_DETECT_FAULT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack HW Current Detect Fault")),
- RACK_HW_ACTOR_NOT_CLOSE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_HW_ACTOR_NOT_CLOSE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack HW Actor Not Close")),
- RACK_HW_ACTOR_NOT_OPEN(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_HW_ACTOR_NOT_OPEN(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack HW Actor Not Open")),
- RACK_HW_FUSE_BROKEN(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_HW_FUSE_BROKEN(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack HW Fuse Broken")),
- RACK_SYSTEM_AFE_OVER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+
+ // Rack System Fault Detail
+ RACK_SYSTEM_AFE_OVER_TEMPERATURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack System AFE Over Temperature")),
- RACK_SYSTEM_AFE_UNDER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_SYSTEM_AFE_UNDER_TEMPERATURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack System AFE Under Temperature")),
- RACK_SYSTEM_AFE_OVER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_SYSTEM_AFE_OVER_VOLTAGE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack System AFE Over Voltage")),
- RACK_SYSTEM_AFE_UNDER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_SYSTEM_AFE_UNDER_VOLTAGE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack System AFE Over Temperature")),
- RACK_SYSTEM_HIGH_TEMPERATURE_PERMANENT_FAILURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_SYSTEM_HIGH_TEMPERATURE_PERMANENT_FAILURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack System High Temperature Permanent Failure")),
- RACK_SYSTEM_LOW_TEMPERATURE_PERMANENT_FAILURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_SYSTEM_LOW_TEMPERATURE_PERMANENT_FAILURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack System Low Temperature Permanent Failure")),
- RACK_SYSTEM_HIGH_CELL_VOLTAGE_PERMANENT_FAILURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_SYSTEM_HIGH_CELL_VOLTAGE_PERMANENT_FAILURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack System High Cell Voltage Permanent Failure")),
- RACK_SYSTEM_LOW_CELL_VOLTAGE_PERMANENT_FAILURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_SYSTEM_LOW_CELL_VOLTAGE_PERMANENT_FAILURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack System Low Cell Voltage Permanent Failure")),
- RACK_SYSTEM_SHORT_CIRCUIT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ RACK_SYSTEM_SHORT_CIRCUIT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Rack System Low Cell Voltage Permanent Failure")),
UPPER_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.VOLT) //
.accessMode(AccessMode.READ_WRITE) //
.text("CV Point")),
- BCU_BMS_SOFTWARE_VERSION(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("Bcu Bms Software Version")),
- BCU_BMS_HARDWARE_VERSION(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("Bcu Bms Hardware Version")),
- BCU_STATUS_ALARM(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+
+ // BCU Status Flags
+ STATUS_ALARM(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Status Alarm")),
- BCU_STATUS_WARNING(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ STATUS_WARNING(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Status WARNNG")),
- BCU_STATUS_FAULT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ STATUS_FAULT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Status BCU Status Fault")),
- BCU_STATUS_PFET(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ STATUS_PFET(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Status Pre-Charge FET On/Off")),
- BCU_STATUS_CFET(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ STATUS_CFET(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Status Charge FET On/Off")),
- BCU_STATUS_DFET(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ STATUS_DFET(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Status Discharge FET On/Off")),
- BCU_STATUS_BATTERY_IDLE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ STATUS_BATTERY_IDLE(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Status Battery Idle")),
- BCU_STATUS_BATTERY_CHARGING(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ STATUS_BATTERY_CHARGING(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Status Battery Charging")),
- BCU_STATUS_BATTERY_DISCHARGING(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ STATUS_BATTERY_DISCHARGING(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Status Battery Discharging")),
- BCU_PRE_ALARM_CELL_OVER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+
+ // Bcu Alarm Flags
+ PRE_ALARM_CELL_OVER_VOLTAGE(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Alarm Cell Over Voltage")),
- BCU_PRE_ALARM_CELL_UNDER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ PRE_ALARM_CELL_UNDER_VOLTAGE(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Alarm Cell Under Voltage")),
- BCU_PRE_ALARM_OVER_CHARGING_CURRENT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ PRE_ALARM_OVER_CHARGING_CURRENT(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Alarm Over Charging Current")),
- BCU_PRE_ALARM_OVER_DISCHARGING_CURRENT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ PRE_ALARM_OVER_DISCHARGING_CURRENT(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Alarm Over Discharging Current")),
- BCU_PRE_ALARM_OVER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ PRE_ALARM_OVER_TEMPERATURE(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Alarm Over Temperature")),
- BCU_PRE_ALARM_UNDER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ PRE_ALARM_UNDER_TEMPERATURE(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Alarm Under Temperature")),
- BCU_PRE_ALARM_CELL_VOLTAGE_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ PRE_ALARM_CELL_VOLTAGE_DIFFERENCE(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Alarm Cell Voltage Difference")),
- BCU_PRE_ALARM_BCU_TEMP_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ PRE_ALARM_BCU_TEMP_DIFFERENCE(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Alarm BCU Temperature Difference")),
- BCU_PRE_ALARM_UNDER_SOC(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ PRE_ALARM_UNDER_SOC(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Alarm Under SOC")),
- BCU_PRE_ALARM_UNDER_SOH(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ PRE_ALARM_UNDER_SOH(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Alarm Under SOH")),
- BCU_PRE_ALARM_OVER_CHARGING_POWER(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ PRE_ALARM_OVER_CHARGING_POWER(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Alarm Over Charging Power")),
- BCU_PRE_ALARM_OVER_DISCHARGING_POWER(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ PRE_ALARM_OVER_DISCHARGING_POWER(Doc.of(Level.INFO) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Alarm Over Discharging Power")),
- BCU_LEVEL_1_CELL_OVER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+
+ // Bcu Warning Flags
+ LEVEL_1_CELL_OVER_VOLTAGE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Warning Cell Over Voltage")),
- BCU_LEVEL_1_CELL_UNDER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_1_CELL_UNDER_VOLTAGE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Warning Cell Under Voltage")),
- BCU_LEVEL_1_OVER_CHARGING_CURRENT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_1_OVER_CHARGING_CURRENT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Warning Over Charging Current")),
- BCU_LEVEL_1_OVER_DISCHARGING_CURRENT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_1_OVER_DISCHARGING_CURRENT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Warning Over Discharging Current")),
- BCU_LEVEL_1_OVER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_1_OVER_TEMPERATURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Warning Over Temperature")),
- BCU_LEVEL_1_UNDER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_1_UNDER_TEMPERATURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Warning Under Temperature")),
- BCU_LEVEL_1_CELL_VOLTAGE_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_1_CELL_VOLTAGE_DIFFERENCE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Warning Cell Voltage Difference")),
- BCU_LEVEL_1_BCU_TEMP_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_1_BCU_TEMP_DIFFERENCE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Warning BCU Temperature Difference")),
- BCU_LEVEL_1_UNDER_SOC(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_1_UNDER_SOC(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Warning Under SOC")),
- BCU_LEVEL_1_UNDER_SOH(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_1_UNDER_SOH(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Warning Under SOH")),
- BCU_LEVEL_1_OVER_CHARGING_POWER(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_1_OVER_CHARGING_POWER(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Warning Over Charging Power")),
- BCU_LEVEL_1_OVER_DISCHARGING_POWER(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_1_OVER_DISCHARGING_POWER(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Warning Over Discharging Power")),
- BCU_LEVEL_2_CELL_OVER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+
+ // Bcu Fault Flags
+ LEVEL_2_CELL_OVER_VOLTAGE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Fault Cell Over Voltage")),
- BCU_LEVEL_2_CELL_UNDER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_2_CELL_UNDER_VOLTAGE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Fault Cell Under Voltage")),
- BCU_LEVEL_2_OVER_CHARGING_CURRENT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_2_OVER_CHARGING_CURRENT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Fault Over Charging Current")),
- BCU_LEVEL_2_OVER_DISCHARGING_CURRENT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_2_OVER_DISCHARGING_CURRENT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Fault Over Discharging Current")),
- BCU_LEVEL_2_OVER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_2_OVER_TEMPERATURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Fault Over Temperature")),
- BCU_LEVEL_2_UNDER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_2_UNDER_TEMPERATURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Fault Under Temperature")),
- BCU_LEVEL_2_CELL_VOLTAGE_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_2_CELL_VOLTAGE_DIFFERENCE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Fault Cell Voltage Difference")),
- BCU_LEVEL_2_BCU_TEMP_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_2_BCU_TEMP_DIFFERENCE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Fault BCU Temperature Difference")),
- BCU_LEVEL_2_TEMPERATURE_DIFFERENCE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_2_TEMPERATURE_DIFFERENCE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Fault BCU Temperature Difference")),
- BCU_LEVEL_2_INTERNAL_COMMUNICATION(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_2_INTERNAL_COMMUNICATION(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Fault Internal Communication")),
- BCU_LEVEL_2_EXTERNAL_COMMUNICATION(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_2_EXTERNAL_COMMUNICATION(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Fault External Communication")),
- BCU_LEVEL_2_PRECHARGE_FAIL(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_2_PRECHARGE_FAIL(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Fault Pre-Charge Fail")),
- BCU_LEVEL_2_PARALLEL_FAIL(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_2_PARALLEL_FAIL(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Fault Parallel Fail")),
- BCU_LEVEL_2_SYSTEM_FAIL(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_2_SYSTEM_FAIL(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Fault System Fault")),
- BCU_LEVEL_2_HARDWARE_FAIL(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ LEVEL_2_HARDWARE_FAIL(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Fault Hardware Fault")),
- BCU_HW_AFE_COMMUNICAITON_FAULT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+
+ // Bcu HW Fault Detail
+ HW_AFE_COMMUNICAITON_FAULT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU HW AFE Communication Fault")),
- BCU_HW_ACTOR_DRIVER_FAULT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ HW_ACTOR_DRIVER_FAULT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU HW Actor Driver Fault")),
- BCU_HW_EEPROM_COMMUNICATION_FAULT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ HW_EEPROM_COMMUNICATION_FAULT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU HW EEPROM Communication Fault")),
- BCU_HW_VOLTAGE_DETECT_FAULT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ HW_VOLTAGE_DETECT_FAULT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU HW Voltage Detect Fault")),
- BCU_HW_TEMPERATURE_DETECT_FAULT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ HW_TEMPERATURE_DETECT_FAULT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU HW Temperaure Detect Fault")),
- BCU_HW_CURRENT_DETECT_FAULT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ HW_CURRENT_DETECT_FAULT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU HW Current Detect Fault")),
- BCU_HW_ACTOR_NOT_CLOSE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ HW_ACTOR_NOT_CLOSE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU HW Actor Not Close Fault")),
- BCU_HW_ACTOR_NOT_OPEN(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ HW_ACTOR_NOT_OPEN(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU HW Actor Not Open")),
- BCU_HW_FUSE_BROKEN(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BCU HW Fuse Broken Fault ")),
- BCU_SYSTEM_AFE_OVER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE)//
+ HW_FUSE_BROKEN(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
+ .text("BCU HW Fuse Broken Fault")),
+
+ // Bcu System Fault Detail
+ SYSTEM_AFE_OVER_TEMPERATURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY)//
.text("BCU System AFE Over Temperature Fault")),
- BCU_SYSTEM_AFE_UNDER_TEMPERATURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ SYSTEM_AFE_UNDER_TEMPERATURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU System AFE Under Temperature Fault")),
- BCU_SYSTEM_AFE_OVER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ SYSTEM_AFE_OVER_VOLTAGE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU System AFE Over Voltage Fault")),
- BCU_SYSTEM_AFE_UNDER_VOLTAGE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ SYSTEM_AFE_UNDER_VOLTAGE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU System AFE Under Voltage Fault")),
- BCU_SYSTEM_HIGH_TEMPERATURE_PERMANENT_FAILURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ SYSTEM_HIGH_TEMPERATURE_PERMANENT_FAILURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU System High Temperature Permanent Fault")),
- BCU_SYSTEM_LOW_TEMPERATURE_PERMANENT_FAILURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ SYSTEM_LOW_TEMPERATURE_PERMANENT_FAILURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU System Low Temperature Permanent Fault")),
- BCU_SYSTEM_HIGH_CELL_VOLTAGE_PERMANENT_FAILURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ SYSTEM_HIGH_CELL_VOLTAGE_PERMANENT_FAILURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU System High Cell Voltage Permanent Fault")),
- BCU_SYSTEM_LOW_CELL_VOLTAGE_PERMANENT_FAILURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ SYSTEM_LOW_CELL_VOLTAGE_PERMANENT_FAILURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU System Low Cell Voltage Permanent Fault")),
- BCU_SYSTEM_LOW_CELL_VOLTAGE_FAILURE(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ BCU_SYSTEM_LOW_CELL_VOLTAGE_FAILURE(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU System Low Cell Voltage Permanent Fault")),
- BCU_SYSTEM_SHORT_CIRCUIT(Doc.of(OpenemsType.BOOLEAN) //
- .accessMode(AccessMode.READ_WRITE) //
+ SYSTEM_SHORT_CIRCUIT(Doc.of(Level.WARNING) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU System Short Circuit Fault")),
- BCU_SOC(Doc.of(OpenemsType.INTEGER) //
+
+ // Rest of the Bcu registers
+ TOWER_SOC(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.PERCENT) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU SOC")),
BCU_SOH(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.PERCENT) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU SOH")),
BCU_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.VOLT) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Battery BCU Voltage")),
BCU_CURRENT(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.AMPERE) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Battery BCU Current")),
BCU_MIN_CELL_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Min Cell Voltage")),
BCU_MAX_CELL_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Maxc Cell Voltage")),
- BCU_AVERAGE_CELL_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
+ AVERAGE_CELL_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Average Of All Cell Voltages")),
BCU_MAX_CHARGE_CURRENT(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.AMPERE) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU DC Charge Current Limit")),
- BCU_MIN_CHARGE_CURRENT(Doc.of(OpenemsType.INTEGER) //
+ MIN_CHARGE_CURRENT(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.AMPERE) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU DC Discharge Current Limit")),
BMS_SERIAL_NUMBER(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BMS Serial Number")),
NO_OF_CYCLES(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Number Of Full charged/discharged cycles")),
DESIGN_CAPACITY(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE_HOURS) //
- .accessMode(AccessMode.READ_WRITE) //
+ .unit(Unit.WATT_HOURS) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Design Capacity Of the Module")),
- USABLE_CAPACITY(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE_HOURS) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("Usable Capacity Of The Module")),
+ USEABLE_CAPACITY(Doc.of(OpenemsType.INTEGER) //
+ .unit(Unit.WATT_HOURS) //
+ .accessMode(AccessMode.READ_ONLY) //
+ .text("Useable Cpacity Of The Module")),
REMAINING_CAPACITY(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.AMPERE_HOURS) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("Remaining Capacity Of The Module")),
- BCU_MAX_CELL_VOLTAGE_LIMIT(Doc.of(OpenemsType.INTEGER) //
+ .unit(Unit.WATT_HOURS) //
+ .accessMode(AccessMode.READ_ONLY) //
+ .text("Remaning Cpacity Of The Module")),
+ MAX_CELL_VOLTAGE_LIMIT(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Max Cell Voltage Limit")),
- BCU_MIN_CELL_VOLTAGE_LIMIT(Doc.of(OpenemsType.INTEGER) //
+ MIN_CELL_VOLTAGE_LIMIT(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BCU Min Cell Voltage Limit")),
BMU_NUMBER(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Bmu Number")),
BMU_SOFTWARE_VERSION(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BMU Software Version")),
BMU_HARDWARE_VERSION(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BMU Hardware Version")),
- CELL_1_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 1")),
- CELL_2_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 2")),
- CELL_3_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 3")),
- CELL_4_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 4")),
- CELL_5_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 5")),
- CELL_6_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 6")),
- CELL_7_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 7")),
- CELL_8_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 8")),
- CELL_9_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 9")),
- CELL_10_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 10")),
- CELL_11_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 11")),
- CELL_12_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 12")),
- CELL_13_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 13")),
- CELL_14_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 14")),
- CELL_15_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 15")),
- CELL_16_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIVOLT) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell Voltage of Block 16")),
- BMU_TEMPERATURE_1(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.DEGREE_CELSIUS)//
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Temperature 1")),
- BMU_TEMPERATURE_2(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.DEGREE_CELSIUS)//
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Temperature 2")),
- BMU_TEMPERATURE_3(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.DEGREE_CELSIUS)//
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Temperature 3")),
- BMU_TEMPERATURE_4(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.DEGREE_CELSIUS)//
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Temperature 4")),
- BMU_TEMPERATURE_5(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.DEGREE_CELSIUS)//
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Temperature 5")),
- BMU_TEMPERATURE_6(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.DEGREE_CELSIUS)//
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Temperature 6")),
- BMU_TEMPERATURE_7(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.DEGREE_CELSIUS)//
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Temperature 7")),
- BMU_TEMPERATURE_8(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.DEGREE_CELSIUS)//
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Temperature 8")),
- BMU_CELL_1_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 1 Balancing Status ")),
- BMU_CELL_2_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 2 Balancing Status ")),
- BMU_CELL_3_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 3 Balancing Status ")),
- BMU_CELL_4_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 4 Balancing Status ")),
- BMU_CELL_5_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 5 Balancing Status ")),
- BMU_CELL_6_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 6 Balancing Status ")),
- BMU_CELL_7_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 7 Balancing Status ")),
- BMU_CELL_8_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 8 Balancing Status ")),
- BMU_CELL_9_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 9 Balancing Status ")),
- BMU_CELL_10_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 10 Balancing Status ")),
- BMU_CELL_11_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 11 Balancing Status ")),
- BMU_CELL_12_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 12 Balancing Status ")),
- BMU_CELL_13_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 13 Balancing Status ")),
- BMU_CELL_14_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 14 Balancing Status ")),
- BMU_CELL_15_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 15 Balancing Status ")),
- BMU_CELL_16_BALANCING_STATUS(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
- .text("BMU Cell 16 Balancing Status ")),
BMU_MAX_CELL_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.MILLIVOLT)//
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BMU Max Cell Voltage")),
BMU_MIN_CELL_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.MILLIVOLT)//
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BMU Min Cell Voltage")),
BMU_MAX_TEMPERATURE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.DEGREE_CELSIUS)//
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Max BMU Temperature")),
BMU_MIN_TEMPERATURE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.DEGREE_CELSIUS)//
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Min BMU Temperature")),
SUM_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.VOLT)//
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("BMU Sum Voltage")),
- BMS_CONTROL(Doc.of(OpenemsType.INTEGER) //
- .text("BMS CONTROL(1: Shutdown, 0: no action)")),
+ BMS_CONTROL(Doc.of(BmsControl.values()) //
+ .text("BMS CONTROL(1: Shutdown, 0: no action, 2: Ignore)")),
KEEP_FET_OPEN(Doc.of(OpenemsType.INTEGER) //
- .accessMode(AccessMode.READ_WRITE) //
+ .accessMode(AccessMode.READ_ONLY) //
.text("Keep FET Open (Disconnect the relay; 1:Keep open, 0: normal operation)")),
STATE_MACHINE(Doc.of(State.values()) //
.text("Current State of State-Machine")), //
diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryImpl.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryImpl.java
index 6aac5c6f693..e16e85f2543 100644
--- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryImpl.java
+++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/FeneconHomeBatteryImpl.java
@@ -1,5 +1,6 @@
package io.openems.edge.battery.fenecon.home;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import org.osgi.service.cm.ConfigurationAdmin;
@@ -7,7 +8,6 @@
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.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
@@ -20,8 +20,10 @@
import org.slf4j.LoggerFactory;
import io.openems.common.channel.AccessMode;
+import io.openems.common.channel.Unit;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.common.exceptions.OpenemsException;
+import io.openems.common.types.OpenemsType;
import io.openems.edge.battery.api.Battery;
import io.openems.edge.battery.fenecon.home.statemachine.Context;
import io.openems.edge.battery.fenecon.home.statemachine.StateMachine;
@@ -30,9 +32,12 @@
import io.openems.edge.bridge.modbus.api.BridgeModbus;
import io.openems.edge.bridge.modbus.api.ElementToChannelConverter;
import io.openems.edge.bridge.modbus.api.ModbusProtocol;
+import io.openems.edge.bridge.modbus.api.ModbusUtils;
+import io.openems.edge.bridge.modbus.api.element.AbstractModbusElement;
import io.openems.edge.bridge.modbus.api.element.BitsWordElement;
import io.openems.edge.bridge.modbus.api.element.UnsignedWordElement;
import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask;
+import io.openems.edge.common.channel.Doc;
import io.openems.edge.common.component.OpenemsComponent;
import io.openems.edge.common.event.EdgeEventConstants;
import io.openems.edge.common.modbusslave.ModbusSlave;
@@ -52,6 +57,13 @@
public class FeneconHomeBatteryImpl extends AbstractOpenemsModbusComponent
implements OpenemsComponent, Battery, EventHandler, ModbusSlave, StartStoppable, FeneconHomeBattery {
+ private static final int TEMPERATURE_ADDRESS_OFFSET = 18;
+ private static final int VOLTAGE_ADDRESS_OFFSET = 2;
+ private static final int SENSORS_PER_MODULE = 14;
+ private static final int ADDRESS_OFFSET_FOR_CELL_VOLT_AND_TEMP = 100;
+ private static final int MODULE_MIN_VOLTAGE = 42; // [V]
+ private static final int MODULE_MAX_VOLTAGE = 45;// [V]
+
private final Logger log = LoggerFactory.getLogger(FeneconHomeBatteryImpl.class);
@Reference
@@ -82,14 +94,22 @@ protected void setModbus(BridgeModbus modbus) {
@Activate
void activate(ComponentContext context, Config config) throws OpenemsException {
+ this.config = config;
+ // Asynchronously read numberOfTowers and numberOfModulesPerTower
+ this.getNumberOfTowers().thenAccept(numberOfTowers -> {
+ this.getNumberOfModulesPerTowers().thenAccept(numberOfModulesPerTower -> {
+ int chargeMaxVoltageValue = numberOfModulesPerTower * MODULE_MAX_VOLTAGE;
+ // Set Battery Charge Max Voltage
+ this._setChargeMaxVoltage(chargeMaxVoltageValue);
+ // Set Battery Discharge Min Voltage
+ int minDischargeVoltageValue = numberOfModulesPerTower * MODULE_MIN_VOLTAGE;
+ this._setDischargeMinVoltage(minDischargeVoltageValue);
+ // Initialize available Tower- and Module-Channels dynamically.
+ this.initializeTowerModulesChannels(numberOfTowers, numberOfModulesPerTower);
+ });
+ });
super.activate(context, config.id(), config.alias(), config.enabled(), config.modbusUnitId(), this.cm, "Modbus",
config.modbus_id());
- this.config = config;
- }
-
- @Deactivate
- protected void deactivate() {
- super.deactivate();
}
@Override
@@ -213,47 +233,30 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
.bit(8, FeneconHomeBattery.ChannelId.FAULT_POSITION_BCU_9) //
.bit(9, FeneconHomeBattery.ChannelId.FAULT_POSITION_BCU_10))//
), //
+
new FC3ReadRegistersTask(506, Priority.HIGH, //
- m(new UnsignedWordElement(506)) //
- .m(FeneconHomeBattery.ChannelId.BATTERY_RACK_VOLTAGE,
- ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // [mV]
- .m(Battery.ChannelId.VOLTAGE, ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // [V]
- .build(), //
- m(new UnsignedWordElement(507)) //
- .m(FeneconHomeBattery.ChannelId.BATTERY_RACK_CURRENT,
- ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // [mV]
- .m(Battery.ChannelId.CURRENT, ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // [V]
- .build(),
- m(new UnsignedWordElement(508))//
- .m(FeneconHomeBattery.ChannelId.BATTERY_RACK_SOC,
- ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // [%]
- .m(Battery.ChannelId.SOC, ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // [%]
- .build(), //
- m(new UnsignedWordElement(509)) //
- .m(FeneconHomeBattery.ChannelId.BATTERY_RACK_SOH,
- ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // [%]
- .m(Battery.ChannelId.SOH, ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // [%]
- .build(), //
- m(FeneconHomeBattery.ChannelId.CELL_VOLTAGE_MIN, new UnsignedWordElement(510)),
+ m(Battery.ChannelId.VOLTAGE, new UnsignedWordElement(506),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // [V]
+ m(Battery.ChannelId.CURRENT, new UnsignedWordElement(507),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // [A]
+ m(Battery.ChannelId.SOC, new UnsignedWordElement(508),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // [%]
+ m(Battery.ChannelId.SOH, new UnsignedWordElement(509),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // [%]
+ m(Battery.ChannelId.MIN_CELL_VOLTAGE, new UnsignedWordElement(510)), // [mV]
m(FeneconHomeBattery.ChannelId.ID_OF_CELL_VOLTAGE_MIN, new UnsignedWordElement(511)), //
- m(FeneconHomeBattery.ChannelId.CELL_VOLTAGE_MAX, new UnsignedWordElement(512)), //
+ m(Battery.ChannelId.MAX_CELL_VOLTAGE, new UnsignedWordElement(512)), // [mV]
m(FeneconHomeBattery.ChannelId.ID_OF_CELL_VOLTAGE_MAX, new UnsignedWordElement(513)), //
- m(FeneconHomeBattery.ChannelId.MIN_TEMPERATURE, new UnsignedWordElement(514), //
+ m(FeneconHomeBattery.ChannelId.MIN_TEMPERATURE, new UnsignedWordElement(514),
ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
m(FeneconHomeBattery.ChannelId.ID_OF_MIN_TEMPERATURE, new UnsignedWordElement(515)), //
- m(FeneconHomeBattery.ChannelId.MAX_TEMPERATURE, new UnsignedWordElement(516)), //
+ m(FeneconHomeBattery.ChannelId.MAX_TEMPERATURE, new UnsignedWordElement(516),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
m(FeneconHomeBattery.ChannelId.ID_OF_MAX_TEMPERATURE, new UnsignedWordElement(517)), //
- m(new UnsignedWordElement(518)) //
- .m(FeneconHomeBattery.ChannelId.MAX_CHARGE_CURRENT,
- ElementToChannelConverter.SCALE_FACTOR_MINUS_1) //
- .m(Battery.ChannelId.CHARGE_MAX_CURRENT, ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // [%]
- .build(), //
- m(new UnsignedWordElement(519)) //
- .m(FeneconHomeBattery.ChannelId.MAX_DISCHARGE_CURRENT,
- ElementToChannelConverter.SCALE_FACTOR_MINUS_1)
- .m(Battery.ChannelId.DISCHARGE_MAX_CURRENT,
- ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // [%]
- .build(), //
+ m(Battery.ChannelId.CHARGE_MAX_CURRENT, new UnsignedWordElement(518),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // [A]
+ m(Battery.ChannelId.DISCHARGE_MAX_CURRENT, new UnsignedWordElement(519), //
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // [A]
m(FeneconHomeBattery.ChannelId.MAX_DC_CHARGE_CURRENT_LIMIT_PER_BCU,
new UnsignedWordElement(520), //
ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
@@ -263,16 +266,8 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
m(FeneconHomeBattery.ChannelId.RACK_NUMBER_OF_BATTERY_BCU, new UnsignedWordElement(522)), //
m(FeneconHomeBattery.ChannelId.RACK_NUMBER_OF_CELLS_IN_SERIES_PER_MODULE,
new UnsignedWordElement(523)), //
- m(new UnsignedWordElement(524)) //
- .m(FeneconHomeBattery.ChannelId.RACK_MAX_CELL_VOLTAGE_LIMIT,
- ElementToChannelConverter.DIRECT_1_TO_1)
- .m(Battery.ChannelId.MAX_CELL_VOLTAGE, ElementToChannelConverter.DIRECT_1_TO_1) // [%]
- .build(), //
- m(new UnsignedWordElement(525)) //
- .m(FeneconHomeBattery.ChannelId.RACK_MAX_CELL_VOLTAGE_LIMIT,
- ElementToChannelConverter.DIRECT_1_TO_1)
- .m(Battery.ChannelId.MAX_CELL_VOLTAGE, ElementToChannelConverter.DIRECT_1_TO_1) // [%]
- .build(), //
+ m(FeneconHomeBattery.ChannelId.RACK_MAX_CELL_VOLTAGE_LIMIT, new UnsignedWordElement(524)), //
+ m(FeneconHomeBattery.ChannelId.RACK_MIN_CELL_VOLTAGE_LIMIT, new UnsignedWordElement(525)), //
m(new BitsWordElement(526, this) //
.bit(0, FeneconHomeBattery.ChannelId.RACK_HW_AFE_COMMUNICATION_FAULT) //
.bit(1, FeneconHomeBattery.ChannelId.RACK_HW_ACTOR_DRIVER_FAULT) //
@@ -294,111 +289,275 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
.bit(7, FeneconHomeBattery.ChannelId.RACK_SYSTEM_LOW_CELL_VOLTAGE_PERMANENT_FAILURE) //
.bit(8, FeneconHomeBattery.ChannelId.RACK_SYSTEM_SHORT_CIRCUIT)), //
m(FeneconHomeBattery.ChannelId.UPPER_VOLTAGE, new UnsignedWordElement(528))), //
- new FC3ReadRegistersTask(10002, Priority.LOW, //
- m(new BitsWordElement(10002, this) //
- .bit(0, FeneconHomeBattery.ChannelId.BCU_STATUS_ALARM) //
- .bit(1, FeneconHomeBattery.ChannelId.BCU_STATUS_WARNING) //
- .bit(2, FeneconHomeBattery.ChannelId.BCU_STATUS_FAULT) //
- .bit(3, FeneconHomeBattery.ChannelId.BCU_STATUS_PFET) //
- .bit(4, FeneconHomeBattery.ChannelId.BCU_STATUS_CFET) //
- .bit(5, FeneconHomeBattery.ChannelId.BCU_STATUS_DFET) //
- .bit(6, FeneconHomeBattery.ChannelId.BCU_STATUS_BATTERY_IDLE) //
- .bit(7, FeneconHomeBattery.ChannelId.BCU_STATUS_BATTERY_CHARGING) //
- .bit(8, FeneconHomeBattery.ChannelId.BCU_STATUS_BATTERY_DISCHARGING)), //
- m(new BitsWordElement(10003, this) //
- .bit(0, FeneconHomeBattery.ChannelId.BCU_PRE_ALARM_CELL_OVER_VOLTAGE) //
- .bit(1, FeneconHomeBattery.ChannelId.BCU_PRE_ALARM_CELL_UNDER_VOLTAGE) //
- .bit(2, FeneconHomeBattery.ChannelId.BCU_PRE_ALARM_OVER_CHARGING_CURRENT) //
- .bit(3, FeneconHomeBattery.ChannelId.BCU_PRE_ALARM_OVER_DISCHARGING_CURRENT) //
- .bit(4, FeneconHomeBattery.ChannelId.BCU_PRE_ALARM_OVER_TEMPERATURE) //
- .bit(5, FeneconHomeBattery.ChannelId.BCU_PRE_ALARM_UNDER_TEMPERATURE) //
- .bit(6, FeneconHomeBattery.ChannelId.BCU_PRE_ALARM_CELL_VOLTAGE_DIFFERENCE) //
- .bit(7, FeneconHomeBattery.ChannelId.BCU_PRE_ALARM_BCU_TEMP_DIFFERENCE) //
- .bit(8, FeneconHomeBattery.ChannelId.BCU_PRE_ALARM_UNDER_SOC) //
- .bit(9, FeneconHomeBattery.ChannelId.BCU_PRE_ALARM_UNDER_SOH) //
- .bit(10, FeneconHomeBattery.ChannelId.BCU_PRE_ALARM_OVER_CHARGING_POWER) //
- .bit(11, FeneconHomeBattery.ChannelId.BCU_PRE_ALARM_OVER_DISCHARGING_POWER) //
- ), //
- m(new BitsWordElement(10004, this) //
- .bit(0, FeneconHomeBattery.ChannelId.BCU_LEVEL_1_CELL_OVER_VOLTAGE) //
- .bit(1, FeneconHomeBattery.ChannelId.BCU_LEVEL_1_CELL_UNDER_VOLTAGE) //
- .bit(2, FeneconHomeBattery.ChannelId.BCU_LEVEL_1_OVER_CHARGING_CURRENT) //
- .bit(3, FeneconHomeBattery.ChannelId.BCU_LEVEL_1_OVER_DISCHARGING_CURRENT) //
- .bit(4, FeneconHomeBattery.ChannelId.BCU_LEVEL_1_OVER_TEMPERATURE) //
- .bit(5, FeneconHomeBattery.ChannelId.BCU_LEVEL_1_UNDER_TEMPERATURE) //
- .bit(6, FeneconHomeBattery.ChannelId.BCU_LEVEL_1_CELL_VOLTAGE_DIFFERENCE) //
- .bit(7, FeneconHomeBattery.ChannelId.BCU_LEVEL_1_BCU_TEMP_DIFFERENCE) //
- .bit(8, FeneconHomeBattery.ChannelId.BCU_LEVEL_1_UNDER_SOC) //
- .bit(9, FeneconHomeBattery.ChannelId.BCU_LEVEL_1_UNDER_SOH) //
- .bit(10, FeneconHomeBattery.ChannelId.BCU_LEVEL_1_OVER_CHARGING_POWER) //
- .bit(11, FeneconHomeBattery.ChannelId.BCU_LEVEL_1_OVER_DISCHARGING_POWER) //
- ), //
- m(new BitsWordElement(10005, this) //
- .bit(0, FeneconHomeBattery.ChannelId.BCU_LEVEL_2_CELL_OVER_VOLTAGE) //
- .bit(1, FeneconHomeBattery.ChannelId.BCU_LEVEL_2_CELL_UNDER_VOLTAGE) //
- .bit(2, FeneconHomeBattery.ChannelId.BCU_LEVEL_2_OVER_CHARGING_CURRENT) //
- .bit(3, FeneconHomeBattery.ChannelId.BCU_LEVEL_2_OVER_DISCHARGING_CURRENT) //
- .bit(4, FeneconHomeBattery.ChannelId.BCU_LEVEL_2_OVER_TEMPERATURE) //
- .bit(5, FeneconHomeBattery.ChannelId.BCU_LEVEL_2_UNDER_TEMPERATURE) //
- .bit(6, FeneconHomeBattery.ChannelId.BCU_LEVEL_2_CELL_VOLTAGE_DIFFERENCE) //
- .bit(7, FeneconHomeBattery.ChannelId.BCU_LEVEL_2_BCU_TEMP_DIFFERENCE) //
- .bit(8, FeneconHomeBattery.ChannelId.BCU_LEVEL_2_TEMPERATURE_DIFFERENCE) //
- .bit(9, FeneconHomeBattery.ChannelId.BCU_LEVEL_2_INTERNAL_COMMUNICATION) //
- .bit(10, FeneconHomeBattery.ChannelId.BCU_LEVEL_2_EXTERNAL_COMMUNICATION) //
- .bit(11, FeneconHomeBattery.ChannelId.BCU_LEVEL_2_PRECHARGE_FAIL) //
- .bit(12, FeneconHomeBattery.ChannelId.BCU_LEVEL_2_PARALLEL_FAIL) //
- .bit(13, FeneconHomeBattery.ChannelId.BCU_LEVEL_2_SYSTEM_FAIL) //
- .bit(14, FeneconHomeBattery.ChannelId.BCU_LEVEL_2_HARDWARE_FAIL)), //
- m(new BitsWordElement(10006, this) //
- .bit(0, FeneconHomeBattery.ChannelId.BCU_HW_AFE_COMMUNICAITON_FAULT) //
- .bit(1, FeneconHomeBattery.ChannelId.BCU_HW_ACTOR_DRIVER_FAULT) //
- .bit(2, FeneconHomeBattery.ChannelId.BCU_HW_EEPROM_COMMUNICATION_FAULT) //
- .bit(3, FeneconHomeBattery.ChannelId.BCU_HW_VOLTAGE_DETECT_FAULT) //
- .bit(4, FeneconHomeBattery.ChannelId.BCU_HW_TEMPERATURE_DETECT_FAULT) //
- .bit(5, FeneconHomeBattery.ChannelId.BCU_HW_CURRENT_DETECT_FAULT) //
- .bit(6, FeneconHomeBattery.ChannelId.BCU_HW_ACTOR_NOT_CLOSE) //
- .bit(7, FeneconHomeBattery.ChannelId.BCU_HW_ACTOR_NOT_OPEN) //
- .bit(8, FeneconHomeBattery.ChannelId.BCU_HW_FUSE_BROKEN)), //
- m(new BitsWordElement(10007, this) //
- .bit(0, FeneconHomeBattery.ChannelId.BCU_SYSTEM_AFE_OVER_TEMPERATURE) //
- .bit(1, FeneconHomeBattery.ChannelId.BCU_SYSTEM_AFE_UNDER_TEMPERATURE) //
- .bit(2, FeneconHomeBattery.ChannelId.BCU_SYSTEM_AFE_OVER_VOLTAGE) //
- .bit(3, FeneconHomeBattery.ChannelId.BCU_SYSTEM_AFE_UNDER_VOLTAGE) //
- .bit(4, FeneconHomeBattery.ChannelId.BCU_SYSTEM_HIGH_TEMPERATURE_PERMANENT_FAILURE) //
- .bit(5, FeneconHomeBattery.ChannelId.BCU_SYSTEM_LOW_TEMPERATURE_PERMANENT_FAILURE) //
- .bit(6, FeneconHomeBattery.ChannelId.BCU_SYSTEM_HIGH_CELL_VOLTAGE_PERMANENT_FAILURE) //
- .bit(7, FeneconHomeBattery.ChannelId.BCU_SYSTEM_LOW_CELL_VOLTAGE_PERMANENT_FAILURE) //
- .bit(8, FeneconHomeBattery.ChannelId.BCU_SYSTEM_SHORT_CIRCUIT)), //
- m(FeneconHomeBattery.ChannelId.BCU_SOC, new UnsignedWordElement(10008), // [%]
- ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
- m(FeneconHomeBattery.ChannelId.BCU_SOH, new UnsignedWordElement(10009), // [%]
- ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
- m(FeneconHomeBattery.ChannelId.BCU_VOLTAGE, new UnsignedWordElement(10010), // [V]
- ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
- m(FeneconHomeBattery.ChannelId.BCU_CURRENT, new UnsignedWordElement(10011), // [A]
- ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
- m(FeneconHomeBattery.ChannelId.BCU_MIN_CELL_VOLTAGE, new UnsignedWordElement(10012)), // [mV]
- m(FeneconHomeBattery.ChannelId.BCU_MAX_CELL_VOLTAGE, new UnsignedWordElement(10013)), // [mV]
- m(FeneconHomeBattery.ChannelId.BCU_AVERAGE_CELL_VOLTAGE, new UnsignedWordElement(10014)), //
- m(FeneconHomeBattery.ChannelId.BCU_MAX_CHARGE_CURRENT, new UnsignedWordElement(10015)), //
- m(FeneconHomeBattery.ChannelId.BCU_MIN_CHARGE_CURRENT, new UnsignedWordElement(10016)), //
- m(FeneconHomeBattery.ChannelId.BMS_SERIAL_NUMBER, new UnsignedWordElement(10017)), //
- m(FeneconHomeBattery.ChannelId.NO_OF_CYCLES, new UnsignedWordElement(10018)), //
- m(FeneconHomeBattery.ChannelId.DESIGN_CAPACITY, new UnsignedWordElement(10019), //
- ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // [Ah]
- m(new UnsignedWordElement(10020)) //
- .m(FeneconHomeBattery.ChannelId.USABLE_CAPACITY,
- ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // [mV]
- .m(Battery.ChannelId.CAPACITY, ElementToChannelConverter.DIRECT_1_TO_1) // [V]
- .build(), //
- m(FeneconHomeBattery.ChannelId.REMAINING_CAPACITY, new UnsignedWordElement(10021), //
- ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // [Ah]
- m(FeneconHomeBattery.ChannelId.BCU_MAX_CELL_VOLTAGE_LIMIT, new UnsignedWordElement(10022)), //
- m(FeneconHomeBattery.ChannelId.BCU_MIN_CELL_VOLTAGE_LIMIT, new UnsignedWordElement(10023)), //
- m(FeneconHomeBattery.ChannelId.BMU_NUMBER, new UnsignedWordElement(10024))), //
new FC3ReadRegistersTask(44000, Priority.HIGH, //
m(FeneconHomeBattery.ChannelId.BMS_CONTROL, new UnsignedWordElement(44000)) //
- ));//
+ ));
+ }
+
+ private void initializeTowerModulesChannels(int numberOfTowers, int numberOfModulePerTower) {
+ try {
+ for (int t = 1; t <= numberOfTowers; t++) {
+ final int towerOffset = (t - 1) * 2000 + 10000;
+ this.getModbusProtocol().addTasks(//
+ new FC3ReadRegistersTask(towerOffset + 2, Priority.LOW, //
+ m(new BitsWordElement(towerOffset + 2, this)//
+ .bit(0, this.generateTowerChannel(t, "STATUS_ALARM")) //
+ .bit(1, this.generateTowerChannel(t, "STATUS_WARNING")) //
+ .bit(2, this.generateTowerChannel(t, "STATUS_FAULT")) //
+ .bit(3, this.generateTowerChannel(t, "STATUS_PFET")) //
+ .bit(4, this.generateTowerChannel(t, "STATUS_CFET")) //
+ .bit(5, this.generateTowerChannel(t, "STATUS_DFET")) //
+ .bit(6, this.generateTowerChannel(t, "STATUS_BATTERY_IDLE")) //
+ .bit(7, this.generateTowerChannel(t, "STATUS_BATTERY_CHARGING")) //
+ .bit(8, this.generateTowerChannel(t, "STATUS_BATTERY_DISCHARGING"))//
+ ), //
+ m(new BitsWordElement(towerOffset + 3, this)
+ .bit(0, this.generateTowerChannel(t, "PRE_ALARM_CELL_OVER_VOLTAGE")) //
+ .bit(1, this.generateTowerChannel(t, "PRE_ALARM_CELL_UNDER_VOLTAGE")) //
+ .bit(2, this.generateTowerChannel(t, "PRE_ALARM_OVER_CHARGING_CURRENT")) //
+ .bit(3, this.generateTowerChannel(t, "PRE_ALARM_OVER_DISCHARGING_CURRENT")) //
+ .bit(4, this.generateTowerChannel(t, "PRE_ALARM_OVER_TEMPERATURE")) //
+ .bit(5, this.generateTowerChannel(t, "PRE_ALARM_UNDER_TEMPERATURE")) //
+ .bit(6, this.generateTowerChannel(t, "PRE_ALARM_CELL_VOLTAGE_DIFFERENCE")) //
+ .bit(7, this.generateTowerChannel(t, "PRE_ALARM_BCU_TEMP_DIFFERENCE")) //
+ .bit(8, this.generateTowerChannel(t, "PRE_ALARM_UNDER_SOC")) //
+ .bit(9, this.generateTowerChannel(t, "PRE_ALARM_UNDER_SOH")) //
+ .bit(10, this.generateTowerChannel(t, "PRE_ALARM_OVER_CHARGING_POWER")) //
+ .bit(11, this.generateTowerChannel(t, "PRE_ALARM_OVER_DISCHARGING_POWER"))), //
+ m(new BitsWordElement(towerOffset + 4, this)
+ .bit(0, this.generateTowerChannel(t, "LEVEL_1_CELL_OVER_VOLTAGE")) //
+ .bit(1, this.generateTowerChannel(t, "LEVEL_1_CELL_UNDER_VOLTAGE")) //
+ .bit(2, this.generateTowerChannel(t, "LEVEL_1_OVER_CHARGING_CURRENT")) //
+ .bit(3, this.generateTowerChannel(t, "LEVEL_1_OVER_DISCHARGING_CURRENT")) //
+ .bit(4, this.generateTowerChannel(t, "LEVEL_1_OVER_TEMPERATURE")) //
+ .bit(5, this.generateTowerChannel(t, "LEVEL_1_UNDER_TEMPERATURE")) //
+ .bit(6, this.generateTowerChannel(t, "LEVEL_1_CELL_VOLTAGE_DIFFERENCE")) //
+ .bit(7, this.generateTowerChannel(t, "LEVEL_1_BCU_TEMP_DIFFERENCE")) //
+ .bit(8, this.generateTowerChannel(t, "LEVEL_1_UNDER_SOC")) //
+ .bit(9, this.generateTowerChannel(t, "LEVEL_1_UNDER_SOH")) //
+ .bit(10, this.generateTowerChannel(t, "LEVEL_1_OVER_CHARGING_POWER")) //
+ .bit(11, this.generateTowerChannel(t, "LEVEL_1_OVER_DISCHARGING_POWER"))),
+ m(new BitsWordElement(towerOffset + 5, this)
+ .bit(0, this.generateTowerChannel(t, "LEVEL_2_CELL_OVER_VOLTAGE")) //
+ .bit(1, this.generateTowerChannel(t, "LEVEL_2_CELL_UNDER_VOLTAGE")) //
+ .bit(2, this.generateTowerChannel(t, "LEVEL_2_OVER_CHARGING_CURRENT")) //
+ .bit(3, this.generateTowerChannel(t, "LEVEL_2_OVER_DISCHARGING_CURRENT")) //
+ .bit(4, this.generateTowerChannel(t, "LEVEL_2_OVER_TEMPERATURE")) //
+ .bit(5, this.generateTowerChannel(t, "LEVEL_2_UNDER_TEMPERATURE")) //
+ .bit(6, this.generateTowerChannel(t, "LEVEL_2_CELL_VOLTAGE_DIFFERENCE")) //
+ .bit(7, this.generateTowerChannel(t, "LEVEL_2_BCU_TEMP_DIFFERENCE")) //
+ .bit(8, this.generateTowerChannel(t, "LEVEL_2_TEMPERATURE_DIFFERENCE")) //
+ .bit(9, this.generateTowerChannel(t, "LEVEL_2_INTERNAL_COMMUNICATION")) //
+ .bit(10, this.generateTowerChannel(t, "LEVEL_2_EXTERNAL_COMMUNICATION")) //
+ .bit(11, this.generateTowerChannel(t, "LEVEL_2_PRECHARGE_FAIL")) //
+ .bit(12, this.generateTowerChannel(t, "LEVEL_2_PARALLEL_FAIL")) //
+ .bit(13, this.generateTowerChannel(t, "LEVEL_2_SYSTEM_FAIL")) //
+ .bit(14, this.generateTowerChannel(t, "LEVEL_2_HARDWARE_FAIL"))), //
+ m(new BitsWordElement(towerOffset + 6, this)
+ .bit(0, this.generateTowerChannel(t, "HW_AFE_COMMUNICAITON_FAULT")) //
+ .bit(1, this.generateTowerChannel(t, "HW_ACTOR_DRIVER_FAULT")) //
+ .bit(2, this.generateTowerChannel(t, "HW_EEPROM_COMMUNICATION_FAULT")) //
+ .bit(3, this.generateTowerChannel(t, "HW_VOLTAGE_DETECT_FAULT")) //
+ .bit(4, this.generateTowerChannel(t, "HW_TEMPERATURE_DETECT_FAULT")) //
+ .bit(5, this.generateTowerChannel(t, "HW_CURRENT_DETECT_FAULT")) //
+ .bit(6, this.generateTowerChannel(t, "HW_ACTOR_NOT_CLOSE")) //
+ .bit(7, this.generateTowerChannel(t, "HW_ACTOR_NOT_OPEN")) //
+ .bit(8, this.generateTowerChannel(t, "HW_FUSE_BROKEN"))), //
+ m(new BitsWordElement(towerOffset + 7, this)
+ .bit(0, this.generateTowerChannel(t, "SYSTEM_AFE_OVER_TEMPERATURE")) //
+ .bit(1, this.generateTowerChannel(t, "SYSTEM_AFE_UNDER_TEMPERATURE")) //
+ .bit(2, this.generateTowerChannel(t, "SYSTEM_AFE_OVER_VOLTAGE")) //
+ .bit(3, this.generateTowerChannel(t, "SYSTEM_AFE_UNDER_VOLTAGE")) //
+ .bit(4, this.generateTowerChannel(t,
+ "SYSTEM_HIGH_TEMPERATURE_PERMANENT_FAILURE")) //
+ .bit(5, this.generateTowerChannel(t,
+ "SYSTEM_LOW_TEMPERATURE_PERMANENT_FAILURE")) //
+ .bit(6, this.generateTowerChannel(t,
+ "SYSTEM_HIGH_CELL_VOLTAGE_PERMANENT_FAILURE")) //
+ .bit(7, this.generateTowerChannel(t,
+ "SYSTEM_LOW_CELL_VOLTAGE_PERMANENT_FAILURE")) //
+ .bit(8, this.generateTowerChannel(t, "SYSTEM_SHORT_CIRCUIT"))), //
+ m(this.generateTowerChannel(t, "_SOC"), new UnsignedWordElement(towerOffset + 8), // [%]
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
+ m(this.generateTowerChannel(t, "_SOH"), new UnsignedWordElement(towerOffset + 9), // [%]
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
+ m(this.generateTowerChannel(t, "_VOLTAGE"), new UnsignedWordElement(towerOffset + 10), // [V]
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
+ m(this.generateTowerChannel(t, "_CURRENT"), new UnsignedWordElement(towerOffset + 11), // [A]
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
+ m(this.generateTowerChannel(t, "_MIN_CELL_VOLTAGE"),
+ new UnsignedWordElement(towerOffset + 12)), // [mV]
+ m(this.generateTowerChannel(t, "_MAX_CELL_VOLTAGE"),
+ new UnsignedWordElement(towerOffset + 13)), // [mV]
+ m(this.generateTowerChannel(t, "_AVARAGE_CELL_VOLTAGE"),
+ new UnsignedWordElement(towerOffset + 14)), //
+ m(this.generateTowerChannel(t, "_MAX_CHARGE_CURRENT"),
+ new UnsignedWordElement(towerOffset + 15)), //
+ m(this.generateTowerChannel(t, "_MIN_CHARGE_CURRENT"),
+ new UnsignedWordElement(towerOffset + 16)), //
+ m(this.generateTowerChannel(t, "_BMS_SERIAL_NUMBER"),
+ new UnsignedWordElement(towerOffset + 17)), //
+ m(this.generateTowerChannel(t, "_NO_OF_CYCLES"),
+ new UnsignedWordElement(towerOffset + 18)), //
+ m(new UnsignedWordElement(towerOffset + 19)) //
+ .m(this.generateTowerChannel(t, "_DESIGN_CAPACITY"),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1) // [Wh]
+ .m(Battery.ChannelId.CAPACITY, ElementToChannelConverter.DIRECT_1_TO_1) //
+ .build(), //
+ m(this.generateTowerChannel(t, "_USABLE_CAPACITY"),
+ new UnsignedWordElement(towerOffset + 20), //
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // [Wh]
+ m(this.generateTowerChannel(t, "_REMAINING_CAPACITY"),
+ new UnsignedWordElement(towerOffset + 21), //
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), // [Wh]
+ m(this.generateTowerChannel(t, "_MAX_CELL_VOLTAGE_LIMIT"),
+ new UnsignedWordElement(towerOffset + 22)), //
+ m(this.generateTowerChannel(t, "_MIN_CELL_VOLTAGE_LIMIT"),
+ new UnsignedWordElement(towerOffset + 23))));
+
+ /*
+ * Dynamically generate Channels and Modbus mappings for Cell-Temperatures and
+ * for Cell-Voltages.Channel-IDs are like "TOWER_1_OFFSET_2_TEMPERATURE_003".
+ * Channel-IDs are like "TOWER_1_OFFSET_2_VOLTAGE_003".
+ */
+ for (int i = 1; i < numberOfModulePerTower + 1; i++) {
+ AbstractModbusElement>[] ameVolt = new AbstractModbusElement>[SENSORS_PER_MODULE];
+ AbstractModbusElement>[] ameTemp = new AbstractModbusElement>[SENSORS_PER_MODULE];
+ for (int j = 0; j < SENSORS_PER_MODULE; j++) {
+ {
+ // Create Voltage Channel
+ ChannelIdImpl channelId = new ChannelIdImpl(//
+ this.getSingleCellPrefix(t, i, j) + "_VOLTAGE",
+ Doc.of(OpenemsType.INTEGER).unit(Unit.VOLT));
+ this.addChannel(channelId);
+ // Create Modbus-Mapping for Voltages
+ UnsignedWordElement uwe = new UnsignedWordElement(towerOffset
+ + i * ADDRESS_OFFSET_FOR_CELL_VOLT_AND_TEMP + VOLTAGE_ADDRESS_OFFSET + j);
+ ameVolt[j] = m(channelId, uwe);
+ }
+ {
+ // Create Temperature Channel
+ ChannelIdImpl channelId = new ChannelIdImpl(//
+ this.getSingleCellPrefix(t, i, j) + "_TEMPERATURE",
+ Doc.of(OpenemsType.INTEGER).unit(Unit.DEZIDEGREE_CELSIUS));
+ this.addChannel(channelId);
+
+ // Create Modbus-Mapping for Temperatures
+ // Cell Temperatures Read Registers for Tower_1 starts from 10000, for Tower_2
+ // 12000, for Tower_3 14000
+ // (t-1)*2000+10000) calculates Tower Offset value
+ UnsignedWordElement uwe = new UnsignedWordElement(towerOffset
+ + i * ADDRESS_OFFSET_FOR_CELL_VOLT_AND_TEMP + TEMPERATURE_ADDRESS_OFFSET + j);
+ ameTemp[j] = m(channelId, uwe);
+ }
+ }
+ this.getModbusProtocol().addTasks(//
+ new FC3ReadRegistersTask(
+ towerOffset + ADDRESS_OFFSET_FOR_CELL_VOLT_AND_TEMP * i + VOLTAGE_ADDRESS_OFFSET,
+ Priority.LOW, ameVolt), //
+ new FC3ReadRegistersTask(//
+ towerOffset + ADDRESS_OFFSET_FOR_CELL_VOLT_AND_TEMP * i
+ + TEMPERATURE_ADDRESS_OFFSET,
+ Priority.LOW, ameTemp));
+ }
+ }
+ } catch (OpenemsException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Gets the Number of Modules Per Tower.
+ *
+ * @return the Number of Modules Per Tower as a {@link CompletableFuture}.
+ * @throws OpenemsException on error
+ */
+ private CompletableFuture getNumberOfModulesPerTowers() {
+ final CompletableFuture result = new CompletableFuture();
+ try {
+ ModbusUtils.readELementOnce(this.getModbusProtocol(), new UnsignedWordElement(10024), true)
+ .thenAccept(numberOfModulesPerTower -> {
+ if (numberOfModulesPerTower == null) {
+ return;
+ }
+ result.complete(numberOfModulesPerTower);
+ });
+ } catch (OpenemsException e) {
+ result.completeExceptionally(e);
+ }
+ return result;
+ }
+
+ /**
+ * Gets the Number of Towers.
+ *
+ * @return the Number of Towers as a {@link CompletableFuture}.
+ */
+ private CompletableFuture getNumberOfTowers() {
+ final CompletableFuture result = new CompletableFuture();
+ try {
+ ModbusUtils.readELementOnce(this.getModbusProtocol(), new UnsignedWordElement(14000), true)
+ .thenAccept(softwareVersionOfTower3 -> {
+ if (softwareVersionOfTower3 == null) {
+ return;
+ }
+ if (softwareVersionOfTower3 != 0) {
+ // Three Towers available
+ result.complete(3);
+ } else {
+ try {
+ ModbusUtils
+ .readELementOnce(this.getModbusProtocol(), new UnsignedWordElement(12000), true)
+ .thenAccept(softwareVersionOfTower2 -> {
+ if (softwareVersionOfTower2 == null) {
+ return;
+ }
+ if (softwareVersionOfTower2 != 0) {
+ // Two Towers available
+ result.complete(2);
+ } else {
+ // One Tower available
+ result.complete(1);
+ }
+ });
+ } catch (OpenemsException e) {
+ result.completeExceptionally(e);
+ }
+ }
+ });
+ } catch (OpenemsException e) {
+ result.completeExceptionally(e);
+ }
+ return result;
+ }
+
+ /**
+ * Generates prefix for Channel-IDs for Cell Temperature and Voltage channels.
+ *
+ *
+ * "%03d" creates string number with leading zeros
+ *
+ * @param num number of the Cell
+ * @param module number of the Module
+ * @param tower number of the Tower
+ * @return a prefix e.g. "TOWER_1_MODULE_2_CELL_003"
+ */
+ private String getSingleCellPrefix(int tower, int module, int num) {
+ return "TOWER_" + tower + "_MODULE_" + module + "_CELL_" + String.format("%03d", num);
+ }
+
+ /**
+ * Generates a Channel-ID for channels that are specific to a tower.
+ *
+ * @param tower number of the Tower
+ * @param channelIdSuffix e.g. "STATUS_ALARM"
+ * @return a channel with Channel-ID "TOWER_1_STATUS_ALARM"
+ */
+ private ChannelIdImpl generateTowerChannel(int tower, String channelIdSuffix) {
+ ChannelIdImpl channelId = new ChannelIdImpl("TOWER_" + tower + "_" + channelIdSuffix,
+ Doc.of(OpenemsType.BOOLEAN));
+ this.addChannel(channelId);
+ return channelId;
}
@Override
diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/enums/BmsControl.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/enums/BmsControl.java
index 818a6875455..896c66ef1e8 100644
--- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/enums/BmsControl.java
+++ b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/enums/BmsControl.java
@@ -4,8 +4,11 @@
public enum BmsControl implements OptionsEnum {
UNDEFINED(-1, "Undefined"), //
+ SWITCHED_ON(0, "Switch ON Pre-charge & Main Power Contactor"), //
SWITCHED_OFF(0x1, "Shut Down Main Power Contactor & Pre-charge"), //
- SWITCHED_ON(0, "Switch ON Pre-charge & Main Power Contactor");
+ // 0x2 is not documented in the modbus protocol, but we still read it from time
+ // to time.
+ IGNORED(0x2, "Switch ON Pre-charge & Main Power Contactor");
private final int value;
private final String name;
diff --git a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/enums/State.java b/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/enums/State.java
deleted file mode 100644
index 0b75a100f76..00000000000
--- a/io.openems.edge.battery.fenecon.home/src/io/openems/edge/battery/fenecon/home/enums/State.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package io.openems.edge.battery.fenecon.home.enums;
-
-import io.openems.common.types.OptionsEnum;
-
-public enum State implements OptionsEnum {
- UNDEFINED("Undefined", -1), //
- PENDING("Pending", 0), //
- OFF("Off", 1), //
- INIT("Initializing", 2), //
- RUNNING("Running", 3), //
- STOPPING("Stopping", 4), //
- ERROR("Error", 5), //
- ERRORDELAY("Errordelay", 6), //
- ERROR_HANDLING("Errordelay", 7), //
- ;
-
- private State(String name, int value) {
- this.name = name;
- this.value = value;
- }
-
- private int value;
- private String name;
-
- @Override
- public int getValue() {
- return this.value;
- }
-
- @Override
- public String getName() {
- return this.name;
- }
-
- @Override
- public OptionsEnum getUndefined() {
- return UNDEFINED;
- }
-
-}
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 e9ddd1ffdf1..9c9cb5e8759 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
@@ -14,7 +14,7 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException {
BmsControl bmsControl = battery.getBmsControl();
// We can no nothing but wait...
- if (bmsControl == BmsControl.SWITCHED_ON) {
+ if (bmsControl == BmsControl.SWITCHED_ON || bmsControl == BmsControl.IGNORED) {
return State.RUNNING;
} else {
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 628b7d7808f..70ec62c7b61 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
@@ -16,7 +16,8 @@ public State runAndGetNextState(Context context) {
return State.UNDEFINED;
}
- if (battery.getBmsControl() != BmsControl.SWITCHED_ON) {
+ if (battery.getBmsControl() != BmsControl.SWITCHED_ON
+ && battery.getBmsControl() != BmsControl.IGNORED) {
return State.UNDEFINED;
}
diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/BatteryProtectionDefinitionSoltaro.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/BatteryProtectionDefinitionSoltaro.java
index a282ed61bba..a3c236f8703 100644
--- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/BatteryProtectionDefinitionSoltaro.java
+++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/BatteryProtectionDefinitionSoltaro.java
@@ -34,8 +34,8 @@ public PolyLine getChargeVoltageToPercent() {
public PolyLine getDischargeVoltageToPercent() {
return PolyLine.create() //
.addPoint(2900, 0) //
- .addPoint(Math.nextUp(2900), 0.05) //
- .addPoint(2920, 0.05) //
+ .addPoint(Math.nextUp(2900), 0.01) //
+ .addPoint(2920, 0.01) //
.addPoint(3000, 1) //
.addPoint(3700, 1) //
.addPoint(Math.nextUp(3700), 0) //
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
deleted file mode 100644
index adaba722950..00000000000
--- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/SoltaroCellCharacteristic.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package io.openems.edge.battery.soltaro;
-
-import io.openems.edge.battery.api.CellCharacteristic;
-
-public class SoltaroCellCharacteristic implements CellCharacteristic {
-
- @Override
- public int getFinalCellDischargeVoltage_mV() {
- return 2_900; //
- }
-
- @Override
- public int getForceChargeCellVoltage_mV() {
- return 2_850; // 0x2046 Cell under voltage Protection + 50 mV (i.e. x2046 ==> 2800)
- }
-
- @Override
- public int getFinalCellChargeVoltage_mV() {
- return 3_650; // 0x0041 Cell Over Voltage Recover / 0x0080 Cell over Voltage Alarm
- }
-
- @Override
- public int getForceDischargeCellVoltage_mV() {
- return 3_680; //
- }
-
-}
\ No newline at end of file
diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/ClusterSettings.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/ClusterSettings.java
deleted file mode 100644
index 7076b86331f..00000000000
--- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/ClusterSettings.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package io.openems.edge.battery.soltaro.cluster;
-
-import io.openems.edge.battery.api.Settings;
-
-public class ClusterSettings implements Settings {
-
- private static final double POWER_FACTOR = 0.02;
- private static final int MINIMUM_CURRENT_AMPERE = 1;
- private static final int TOLERANCE_MILLI_VOLT = 10;
- private static final int MAX_INCREASE_MILLIAMPERE = 300;
-
- private int numberOfUsedRacks = 1;
-
- /**
- * Sets the number of used racks.
- * @param numberOfUsedRacks int
- */
- public void setNumberOfUsedRacks(int numberOfUsedRacks) {
- this.numberOfUsedRacks = numberOfUsedRacks;
- }
-
- @Override
- public int getMaxIncreaseMilliAmpere() {
- return MAX_INCREASE_MILLIAMPERE * this.numberOfUsedRacks;
- }
-
- @Override
- public double getPowerFactor() {
- return POWER_FACTOR;
- }
-
- @Override
- public double getMinimumCurrentAmpere() {
- return MINIMUM_CURRENT_AMPERE * this.numberOfUsedRacks;
- }
-
- @Override
- public int getToleranceMilliVolt() {
- return TOLERANCE_MILLI_VOLT;
- }
-
-}
diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/SoltaroCluster.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/SoltaroCluster.java
index 657668b9f55..af8e314bb96 100644
--- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/SoltaroCluster.java
+++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/SoltaroCluster.java
@@ -89,11 +89,7 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId
.unit(Unit.MILLIAMPERE)), //
SYSTEM_INSULATION(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.OHM)), //
- CLUSTER_MAX_ALLOWED_CHARGE_CURRENT(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIAMPERE)), //
- CLUSTER_MAX_ALLOWED_DISCHARGE_CURRENT(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIAMPERE)), //
-
+
/*
* StateChannels
*/
diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/ClusterVersionB.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/ClusterVersionB.java
index 1a3d6c6d33f..9601b26086c 100644
--- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/ClusterVersionB.java
+++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionb/ClusterVersionB.java
@@ -26,13 +26,12 @@
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.api.SetAllowedCurrents;
+import io.openems.edge.battery.protection.BatteryProtection;
+import io.openems.edge.battery.soltaro.BatteryProtectionDefinitionSoltaro;
import io.openems.edge.battery.soltaro.BatteryState;
import io.openems.edge.battery.soltaro.ModuleParameters;
import io.openems.edge.battery.soltaro.ResetState;
-import io.openems.edge.battery.soltaro.SoltaroCellCharacteristic;
import io.openems.edge.battery.soltaro.State;
-import io.openems.edge.battery.soltaro.cluster.ClusterSettings;
import io.openems.edge.battery.soltaro.cluster.SoltaroCluster;
import io.openems.edge.battery.soltaro.cluster.enums.ClusterStartStop;
import io.openems.edge.battery.soltaro.cluster.enums.RackUsage;
@@ -52,6 +51,7 @@
import io.openems.edge.common.channel.EnumWriteChannel;
import io.openems.edge.common.channel.IntegerWriteChannel;
import io.openems.edge.common.channel.StateChannel;
+import io.openems.edge.common.component.ComponentManager;
import io.openems.edge.common.component.OpenemsComponent;
import io.openems.edge.common.event.EdgeEventConstants;
import io.openems.edge.common.modbusslave.ModbusSlave;
@@ -72,9 +72,6 @@
public class ClusterVersionB extends AbstractOpenemsModbusComponent
implements SoltaroCluster, Battery, OpenemsComponent, EventHandler, ModbusSlave, StartStoppable {
- public static final int DISCHARGE_MAX_A = 0; // default value 0 to avoid damages
- public static final int CHARGE_MAX_A = 0; // default value 0 to avoid damages
-
private static final int ADDRESS_OFFSET_RACK_1 = 0x2000;
private static final int ADDRESS_OFFSET_RACK_2 = 0x3000;
private static final int ADDRESS_OFFSET_RACK_3 = 0x4000;
@@ -86,10 +83,13 @@ public class ClusterVersionB extends AbstractOpenemsModbusComponent
// are used or not
private static final Map RACK_INFO = createRackInfo();
private final Logger log = LoggerFactory.getLogger(ClusterVersionB.class);
- private final SetAllowedCurrents setAllowedCurrents;
+
@Reference
protected ConfigurationAdmin cm;
+ @Reference
+ protected ComponentManager componentManager;
+
// If an error has occurred, this indicates the time when next action could be
// done
private LocalDateTime errorDelayIsOver = null;
@@ -106,7 +106,7 @@ public class ClusterVersionB extends AbstractOpenemsModbusComponent
private ResetState resetState = ResetState.NONE;
private boolean resetDone;
- private ClusterSettings clusterSettings = new ClusterSettings();
+ private BatteryProtection batteryProtection = null;
public ClusterVersionB() {
super(//
@@ -114,14 +114,8 @@ public ClusterVersionB() {
Battery.ChannelId.values(), //
StartStoppable.ChannelId.values(), //
SoltaroCluster.ChannelId.values(), //
- ClusterVersionBChannelId.values() //
- );
- this.setAllowedCurrents = new SetAllowedCurrents(//
- this, //
- new SoltaroCellCharacteristic(), //
- this.clusterSettings, //
- this.channel(SoltaroCluster.ChannelId.CLUSTER_MAX_ALLOWED_CHARGE_CURRENT), //
- this.channel(SoltaroCluster.ChannelId.CLUSTER_MAX_ALLOWED_DISCHARGE_CURRENT) //
+ ClusterVersionBChannelId.values(), //
+ BatteryProtection.ChannelId.values() //
);
}
@@ -151,25 +145,17 @@ void activate(ComponentContext context, Config config) throws OpenemsException {
this.modbusBridgeId = config.modbus_id();
this.batteryState = config.batteryState();
- this._setChargeMaxCurrent(ClusterVersionB.CHARGE_MAX_A);
- this._setDischargeMaxCurrent(ClusterVersionB.DISCHARGE_MAX_A);
+ // Initialize Battery-Protection
+ this.batteryProtection = BatteryProtection.create(this) //
+ .applyBatteryProtectionDefinition(new BatteryProtectionDefinitionSoltaro(), this.componentManager) //
+ .build();
+
this._setChargeMaxVoltage(
this.config.numberOfSlaves() * ModuleParameters.MAX_VOLTAGE_MILLIVOLT.getValue() / 1000);
this._setDischargeMinVoltage(
this.config.numberOfSlaves() * ModuleParameters.MIN_VOLTAGE_MILLIVOLT.getValue() / 1000);
this._setCapacity(
this.config.racks().length * this.config.numberOfSlaves() * this.config.moduleType().getCapacity_Wh());
-
- this.clusterSettings.setNumberOfUsedRacks(calculateUsedRacks(config));
- }
-
- private static int calculateUsedRacks(Config conf) {
- int num = 0;
- if (conf.racks() != null) {
- num = conf.racks().length;
- }
-
- return num;
}
@Override
@@ -181,10 +167,9 @@ public void handleEvent(Event event) {
switch (event.getTopic()) {
case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE:
-
- this.setAllowedCurrents.act();
-
+ this.batteryProtection.apply();
break;
+
case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE:
this.handleBatteryState();
break;
@@ -615,10 +600,10 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
new FC3ReadRegistersTask(0x104A, Priority.HIGH, //
m(SoltaroCluster.ChannelId.SYSTEM_INSULATION, new UnsignedWordElement(0x104A)), //
new DummyRegisterElement(0x104B, 0x104D), //
- m(SoltaroCluster.ChannelId.CLUSTER_MAX_ALLOWED_CHARGE_CURRENT, new UnsignedWordElement(0x104E),
- ElementToChannelConverter.SCALE_FACTOR_2), //
- m(SoltaroCluster.ChannelId.CLUSTER_MAX_ALLOWED_DISCHARGE_CURRENT,
- new UnsignedWordElement(0x104F), ElementToChannelConverter.SCALE_FACTOR_2) //
+ m(BatteryProtection.ChannelId.BP_CHARGE_BMS, new UnsignedWordElement(0x104E),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
+ m(BatteryProtection.ChannelId.BP_DISCHARGE_BMS, new UnsignedWordElement(0x104F),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1) //
), //
new FC3ReadRegistersTask(0x1081, Priority.LOW, //
diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/ClusterVersionCImpl.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/ClusterVersionCImpl.java
index 40c13b38473..498fdfc01d1 100644
--- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/ClusterVersionCImpl.java
+++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/cluster/versionc/ClusterVersionCImpl.java
@@ -25,9 +25,8 @@
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.api.SetAllowedCurrents;
-import io.openems.edge.battery.soltaro.SoltaroCellCharacteristic;
-import io.openems.edge.battery.soltaro.cluster.ClusterSettings;
+import io.openems.edge.battery.protection.BatteryProtection;
+import io.openems.edge.battery.soltaro.BatteryProtectionDefinitionSoltaro;
import io.openems.edge.battery.soltaro.cluster.SoltaroCluster;
import io.openems.edge.battery.soltaro.cluster.enums.Rack;
import io.openems.edge.battery.soltaro.cluster.versionc.statemachine.Context;
@@ -52,6 +51,7 @@
import io.openems.edge.common.channel.EnumReadChannel;
import io.openems.edge.common.channel.IntegerReadChannel;
import io.openems.edge.common.channel.IntegerWriteChannel;
+import io.openems.edge.common.component.ComponentManager;
import io.openems.edge.common.component.OpenemsComponent;
import io.openems.edge.common.event.EdgeEventConstants;
import io.openems.edge.common.modbusslave.ModbusSlave;
@@ -77,18 +77,18 @@ public class ClusterVersionCImpl extends AbstractOpenemsModbusComponent implemen
@Reference
protected ConfigurationAdmin cm;
-
+
+ @Reference
+ protected ComponentManager componentManager;
/**
* Manages the {@link State}s of the StateMachine.
*/
private final StateMachine stateMachine = new StateMachine(State.UNDEFINED);
- private final SetAllowedCurrents setAllowedCurrents;
private Config config;
private Set racks = new HashSet<>();
- private ClusterSettings clusterSettings = new ClusterSettings();
-
+ private BatteryProtection batteryProtection = null;
public ClusterVersionCImpl() {
super(//
@@ -97,16 +97,10 @@ public ClusterVersionCImpl() {
SoltaroBatteryVersionC.ChannelId.values(), //
SoltaroCluster.ChannelId.values(), //
StartStoppable.ChannelId.values(), //
- ClusterVersionC.ChannelId.values() //
+ ClusterVersionC.ChannelId.values(), //
+ BatteryProtection.ChannelId.values() //
);
-
- this.setAllowedCurrents = new SetAllowedCurrents(//
- this, //
- new SoltaroCellCharacteristic(), //
- this.clusterSettings, //
- this.channel(SoltaroCluster.ChannelId.CLUSTER_MAX_ALLOWED_CHARGE_CURRENT), //
- this.channel(SoltaroCluster.ChannelId.CLUSTER_MAX_ALLOWED_DISCHARGE_CURRENT) //
- );
+
}
@Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY)
@@ -139,6 +133,11 @@ void activate(ComponentContext context, Config config) throws OpenemsNamedExcept
return;
}
+ // Initialize Battery-Protection
+ this.batteryProtection = BatteryProtection.create(this) //
+ .applyBatteryProtectionDefinition(new BatteryProtectionDefinitionSoltaro(), this.componentManager) //
+ .build();
+
// Calculate Capacity
int capacity = this.config.numberOfSlaves() * this.config.moduleType().getCapacity_Wh();
this._setCapacity(capacity);
@@ -152,8 +151,6 @@ void activate(ComponentContext context, Config config) throws OpenemsNamedExcept
this._setDischargeMaxCurrent(0 /* default value 0 to avoid damages */);
this._setChargeMaxVoltage(this.config.numberOfSlaves() * Constants.MAX_VOLTAGE_MILLIVOLT / 1000);
this._setDischargeMinVoltage(this.config.numberOfSlaves() * Constants.MIN_VOLTAGE_MILLIVOLT / 1000);
-
- this.clusterSettings.setNumberOfUsedRacks(calculateUsedRacks(config));
}
@Override
@@ -165,7 +162,7 @@ public void handleEvent(Event event) {
case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE:
this.updateChannels();
- this.setAllowedCurrents.act();
+ this.batteryProtection.apply();
break;
case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE:
@@ -252,10 +249,10 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
m(SoltaroCluster.ChannelId.SYSTEM_INSULATION, new UnsignedWordElement(0x104A)), //
new DummyRegisterElement(0x104B, 0x104D), //
- m(SoltaroCluster.ChannelId.CLUSTER_MAX_ALLOWED_CHARGE_CURRENT, new UnsignedWordElement(0x104E),
- ElementToChannelConverter.SCALE_FACTOR_2), //
- m(SoltaroCluster.ChannelId.CLUSTER_MAX_ALLOWED_DISCHARGE_CURRENT, new UnsignedWordElement(0x104F),
- ElementToChannelConverter.SCALE_FACTOR_2)), //
+ m(BatteryProtection.ChannelId.BP_CHARGE_BMS, new UnsignedWordElement(0x104E),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
+ m(BatteryProtection.ChannelId.BP_DISCHARGE_BMS, new UnsignedWordElement(0x104F),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1)), //
new FC3ReadRegistersTask(0x1081, Priority.LOW, //
m(new BitsWordElement(0x1081, this) //
.bit(0, ClusterVersionC.ChannelId.MASTER_PCS_COMMUNICATION_FAILURE) //
@@ -431,12 +428,12 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
m(this.rack(r, RackChannel.MIN_CELL_VOLTAGE), new UnsignedWordElement(r.offset + 0x108)),
m(this.rack(r, RackChannel.MAX_CELL_TEMPERATURE_ID),
new UnsignedWordElement(r.offset + 0x109)),
- m(this.rack(r, RackChannel.MAX_CELL_TEMPERATURE),
- new SignedWordElement(r.offset + 0x10A)),
+ m(this.rack(r, RackChannel.MAX_CELL_TEMPERATURE), new SignedWordElement(r.offset + 0x10A),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1),
m(this.rack(r, RackChannel.MIN_CELL_TEMPERATURE_ID),
new UnsignedWordElement(r.offset + 0x10B)),
- m(this.rack(r, RackChannel.MIN_CELL_TEMPERATURE),
- new SignedWordElement(r.offset + 0x10C)),
+ m(this.rack(r, RackChannel.MIN_CELL_TEMPERATURE), new SignedWordElement(r.offset + 0x10C),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1),
m(this.rack(r, RackChannel.AVERAGE_VOLTAGE), new UnsignedWordElement(r.offset + 0x10D)),
m(this.rack(r, RackChannel.SYSTEM_INSULATION), new UnsignedWordElement(r.offset + 0x10E)),
m(this.rack(r, RackChannel.SYSTEM_MAX_CHARGE_CURRENT),
@@ -965,24 +962,4 @@ public StartStop getStartStopTarget() {
assert false;
return StartStop.UNDEFINED; // can never happen
}
-
- private static int calculateUsedRacks(Config conf) {
- int num = 0;
- if (conf.isRack1Used()) {
- num = num + 1;
- }
- if (conf.isRack2Used()) {
- num = num + 1;
- }
- if (conf.isRack3Used()) {
- num = num + 1;
- }
- if (conf.isRack4Used()) {
- num = num + 1;
- }
- if (conf.isRack5Used()) {
- num = num + 1;
- }
- return num;
- }
}
diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/SingleRackSettings.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/SingleRackSettings.java
deleted file mode 100644
index c9c2b01163a..00000000000
--- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/SingleRackSettings.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package io.openems.edge.battery.soltaro.single;
-
-import io.openems.edge.battery.api.Settings;
-
-public class SingleRackSettings implements Settings {
-
- private static final double POWER_FACTOR = 0.02;
- private static final int MINIMUM_CURRENT_AMPERE = 1;
- private static final int TOLERANCE_MILLI_VOLT = 10;
- private static final int MAX_INCREASE_MILLIAMPERE = 300;
-
- @Override
- public int getMaxIncreaseMilliAmpere() {
- return MAX_INCREASE_MILLIAMPERE;
- }
-
- @Override
- public double getPowerFactor() {
- return POWER_FACTOR;
- }
-
- @Override
- public double getMinimumCurrentAmpere() {
- return MINIMUM_CURRENT_AMPERE;
- }
-
- @Override
- public int getToleranceMilliVolt() {
- return TOLERANCE_MILLI_VOLT;
- }
-
-}
diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versiona/SingleRack.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versiona/SingleRack.java
index 5e536f83d53..ad3483d80a2 100644
--- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versiona/SingleRack.java
+++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versiona/SingleRack.java
@@ -28,12 +28,11 @@
import io.openems.common.exceptions.OpenemsException;
import io.openems.common.types.OpenemsType;
import io.openems.edge.battery.api.Battery;
-import io.openems.edge.battery.api.SetAllowedCurrents;
+import io.openems.edge.battery.protection.BatteryProtection;
+import io.openems.edge.battery.soltaro.BatteryProtectionDefinitionSoltaro;
import io.openems.edge.battery.soltaro.BatteryState;
import io.openems.edge.battery.soltaro.ChargeIndication;
-import io.openems.edge.battery.soltaro.SoltaroCellCharacteristic;
import io.openems.edge.battery.soltaro.State;
-import io.openems.edge.battery.soltaro.single.SingleRackSettings;
import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent;
import io.openems.edge.bridge.modbus.api.BridgeModbus;
import io.openems.edge.bridge.modbus.api.ElementToChannelConverter;
@@ -48,6 +47,7 @@
import io.openems.edge.common.channel.EnumReadChannel;
import io.openems.edge.common.channel.EnumWriteChannel;
import io.openems.edge.common.channel.StateChannel;
+import io.openems.edge.common.component.ComponentManager;
import io.openems.edge.common.component.OpenemsComponent;
import io.openems.edge.common.event.EdgeEventConstants;
import io.openems.edge.common.modbusslave.ModbusSlave;
@@ -71,9 +71,6 @@ public class SingleRack extends AbstractOpenemsModbusComponent
// Default values for the battery ranges
public static final int DISCHARGE_MIN_V = 696;
public static final int CHARGE_MAX_V = 854;
- public static final int DISCHARGE_MAX_A = 0;
- public static final int CHARGE_MAX_A = 0;
-
protected static final int SYSTEM_ON = 1;
protected static final int SYSTEM_OFF = 0;
@@ -88,6 +85,9 @@ public class SingleRack extends AbstractOpenemsModbusComponent
@Reference
protected ConfigurationAdmin cm;
+ @Reference
+ protected ComponentManager componentManager;
+
// If an error has occurred, this indicates the time when next action could be
// done
private LocalDateTime errorDelayIsOver = null;
@@ -100,27 +100,18 @@ public class SingleRack extends AbstractOpenemsModbusComponent
private LocalDateTime pendingTimestamp;
- private final SetAllowedCurrents setAllowedCurrents;
+ private BatteryProtection batteryProtection = null;
public SingleRack() {
super(//
OpenemsComponent.ChannelId.values(), //
StartStoppable.ChannelId.values(), //
Battery.ChannelId.values(), //
- SingleRack.ChannelId.values() //
+ SingleRack.ChannelId.values(), //
+ BatteryProtection.ChannelId.values() //
);
- this._setChargeMaxCurrent(SingleRack.CHARGE_MAX_A);
this._setChargeMaxVoltage(SingleRack.CHARGE_MAX_V);
- this._setDischargeMaxCurrent(SingleRack.DISCHARGE_MAX_A);
this._setDischargeMinVoltage(SingleRack.DISCHARGE_MIN_V);
-
- this.setAllowedCurrents = new SetAllowedCurrents(//
- this, //
- new SoltaroCellCharacteristic(), //
- new SingleRackSettings(), //
- this.channel(SingleRack.ChannelId.SYSTEM_ACCEPT_MAX_CHARGE_CURRENT), //
- this.channel(SingleRack.ChannelId.SYSTEM_ACCEPT_MAX_DISCHARGE_CURRENT) //
- );
}
@Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY)
@@ -137,6 +128,12 @@ void activate(ComponentContext context, Config config) throws OpenemsException {
}
this.modbusBridgeId = config.modbus_id();
this.batteryState = config.batteryState();
+
+ // Initialize Battery-Protection
+ this.batteryProtection = BatteryProtection.create(this) //
+ .applyBatteryProtectionDefinition(new BatteryProtectionDefinitionSoltaro(), this.componentManager) //
+ .build();
+
this._setCapacity(config.capacity() * 1000);
this.initializeCallbacks();
}
@@ -178,8 +175,7 @@ public void handleEvent(Event event) {
switch (event.getTopic()) {
case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE:
-
- this.setAllowedCurrents.act();
+ this.batteryProtection.apply();
break;
case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE:
@@ -341,6 +337,7 @@ private boolean isSystemStopped() {
/**
* Checks whether system has an undefined state.
+ *
* @return true when the system is pending
*/
private boolean isSystemStatePending() {
@@ -355,6 +352,7 @@ private boolean readValueFromBooleanChannel(ChannelId channelId) {
/**
* Returns the statemachine state.
+ *
* @return the statemachine state
*/
public State getStateMachineState() {
@@ -363,6 +361,7 @@ public State getStateMachineState() {
/**
* Sets the state.
+ *
* @param state the State
*/
public void setStateMachineState(State state) {
@@ -372,21 +371,19 @@ public void setStateMachineState(State state) {
/**
* Returns the modbus bridge id.
+ *
* @return the modbus bridge id
*/
public String getModbusBridgeId() {
return this.modbusBridgeId;
}
- @Override
+ @Override
public String debugLog() {
return "SoC:" + this.getSoc() //
+ "|Discharge:" + this.getDischargeMinVoltage() + ";" + this.getDischargeMaxCurrent() //
- + "|Charge:" + this.getChargeMaxVoltage() + ";" + this.getChargeMaxCurrent()
- + "|Running: " + this.isSystemRunning()
- + "|U: " + this.getVoltage()
- + "|I: " + this.getCurrent()
- ;
+ + "|Charge:" + this.getChargeMaxVoltage() + ";" + this.getChargeMaxCurrent() + "|Running: "
+ + this.isSystemRunning() + "|U: " + this.getVoltage() + "|I: " + this.getCurrent();
}
private void startSystem() {
@@ -460,10 +457,6 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
.unit(Unit.NONE)), //
SYSTEM_INSULATION(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.KILOOHM)), //
- SYSTEM_ACCEPT_MAX_CHARGE_CURRENT(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIAMPERE)), //
- SYSTEM_ACCEPT_MAX_DISCHARGE_CURRENT(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIAMPERE)), //
CLUSTER_1_BATTERY_000_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.MILLIVOLT)), //
CLUSTER_1_BATTERY_001_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
@@ -1135,7 +1128,7 @@ public Doc doc() {
}
}
-@Override
+ @Override
protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
return new ModbusProtocol(this, //
new FC6WriteRegisterTask(0x2010, //
@@ -1182,10 +1175,10 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
m(SingleRack.ChannelId.SYSTEM_INSULATION, new UnsignedWordElement(0x2116)) //
), //
new FC3ReadRegistersTask(0x2160, Priority.HIGH, //
- m(SingleRack.ChannelId.SYSTEM_ACCEPT_MAX_CHARGE_CURRENT, new UnsignedWordElement(0x2160), //
- ElementToChannelConverter.SCALE_FACTOR_2), //
- m(SingleRack.ChannelId.SYSTEM_ACCEPT_MAX_DISCHARGE_CURRENT, new UnsignedWordElement(0x2161), //
- ElementToChannelConverter.SCALE_FACTOR_2) //
+ m(BatteryProtection.ChannelId.BP_CHARGE_BMS, new UnsignedWordElement(0x2160),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
+ m(BatteryProtection.ChannelId.BP_DISCHARGE_BMS, new UnsignedWordElement(0x2161),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1) //
), //
new FC3ReadRegistersTask(0x2140, Priority.LOW, //
m(new BitsWordElement(0x2140, this) //
diff --git a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/SingleRackVersionC.java b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/SingleRackVersionC.java
index cd4fc7fe7f2..fe5a97e57ef 100644
--- a/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/SingleRackVersionC.java
+++ b/io.openems.edge.battery.soltaro/src/io/openems/edge/battery/soltaro/single/versionc/SingleRackVersionC.java
@@ -488,10 +488,6 @@ public static enum ChannelId implements io.openems.edge.common.channel.ChannelId
.unit(Unit.MILLIVOLT)), //
CLUSTER_1_SYSTEM_INSULATION(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.KILOOHM)), //
- SYSTEM_MAX_CHARGE_CURRENT(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIAMPERE)),
- SYSTEM_MAX_DISCHARGE_CURRENT(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.MILLIAMPERE)),
POSITIVE_INSULATION(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.KILOOHM)),
NEGATIVE_INSULATION(Doc.of(OpenemsType.INTEGER) //
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 acdf43e630e..ce8043dddab 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,9 +24,8 @@
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.api.SetAllowedCurrents;
-import io.openems.edge.battery.soltaro.SoltaroCellCharacteristic;
-import io.openems.edge.battery.soltaro.single.SingleRackSettings;
+import io.openems.edge.battery.protection.BatteryProtection;
+import io.openems.edge.battery.soltaro.BatteryProtectionDefinitionSoltaro;
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;
@@ -46,6 +45,7 @@
import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask;
import io.openems.edge.bridge.modbus.api.task.FC6WriteRegisterTask;
import io.openems.edge.common.channel.IntegerWriteChannel;
+import io.openems.edge.common.component.ComponentManager;
import io.openems.edge.common.component.OpenemsComponent;
import io.openems.edge.common.event.EdgeEventConstants;
import io.openems.edge.common.modbusslave.ModbusSlave;
@@ -71,28 +71,24 @@ public class SingleRackVersionCImpl extends AbstractOpenemsModbusComponent
@Reference
protected ConfigurationAdmin cm;
+ @Reference
+ protected ComponentManager componentManager;
+
/**
* Manages the {@link State}s of the StateMachine.
*/
private final StateMachine stateMachine = new StateMachine(State.UNDEFINED);
private Config config;
- private SetAllowedCurrents setAllowedCurrents;
-
+ private BatteryProtection batteryProtection = null;
+
public SingleRackVersionCImpl() {
super(//
OpenemsComponent.ChannelId.values(), //
Battery.ChannelId.values(), //
StartStoppable.ChannelId.values(), //
- SingleRackVersionC.ChannelId.values() //
- );
-
- this.setAllowedCurrents = new SetAllowedCurrents(//
- this, //
- new SoltaroCellCharacteristic(), //
- new SingleRackSettings(), //
- this.channel(SingleRackVersionC.ChannelId.SYSTEM_MAX_CHARGE_CURRENT), //
- this.channel(SingleRackVersionC.ChannelId.SYSTEM_MAX_DISCHARGE_CURRENT) //
+ SingleRackVersionC.ChannelId.values(), //
+ BatteryProtection.ChannelId.values() //
);
}
@@ -109,6 +105,11 @@ void activate(ComponentContext context, Config config) throws OpenemsNamedExcept
return;
}
+ // Initialize Battery-Protection
+ this.batteryProtection = BatteryProtection.create(this) //
+ .applyBatteryProtectionDefinition(new BatteryProtectionDefinitionSoltaro(), this.componentManager) //
+ .build();
+
// Calculate Capacity
int capacity = this.config.numberOfSlaves() * this.config.moduleType().getCapacity_Wh();
this._setCapacity(capacity);
@@ -138,9 +139,7 @@ public void handleEvent(Event event) {
switch (event.getTopic()) {
case EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE:
-
- this.setAllowedCurrents.act();
-
+ this.batteryProtection.apply();
break;
case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE:
@@ -244,7 +243,7 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
m(SingleRackVersionC.ChannelId.VOLTAGE_LOW_PROTECTION, new UnsignedWordElement(0x20F3)), //
m(SingleRackVersionC.ChannelId.EMS_COMMUNICATION_TIMEOUT, new UnsignedWordElement(0x20F4)) //
), //
- // Single Cluster Running Status Registers
+ // Single Cluster Running Status Registers
new FC3ReadRegistersTask(0x2100, Priority.HIGH, //
m(new UnsignedWordElement(0x2100)) //
.m(SingleRackVersionC.ChannelId.CLUSTER_1_VOLTAGE,
@@ -291,14 +290,10 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
.build(), //
m(SingleRackVersionC.ChannelId.CLUSTER_1_AVERAGE_VOLTAGE, new UnsignedWordElement(0x210D)), //
m(SingleRackVersionC.ChannelId.CLUSTER_1_SYSTEM_INSULATION, new UnsignedWordElement(0x210E)), //
- m(new UnsignedWordElement(0x210F)) //
- .m(SingleRackVersionC.ChannelId.SYSTEM_MAX_CHARGE_CURRENT,
- ElementToChannelConverter.SCALE_FACTOR_2) //
- .build(), //
- m(new UnsignedWordElement(0x2110)) //
- .m(SingleRackVersionC.ChannelId.SYSTEM_MAX_DISCHARGE_CURRENT,
- ElementToChannelConverter.SCALE_FACTOR_2) //
- .build(), //
+ m(BatteryProtection.ChannelId.BP_CHARGE_BMS, new UnsignedWordElement(0x210F),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
+ m(BatteryProtection.ChannelId.BP_DISCHARGE_BMS, new UnsignedWordElement(0x2110),
+ ElementToChannelConverter.SCALE_FACTOR_MINUS_1), //
m(SingleRackVersionC.ChannelId.POSITIVE_INSULATION, new UnsignedWordElement(0x2111)), //
m(SingleRackVersionC.ChannelId.NEGATIVE_INSULATION, new UnsignedWordElement(0x2112)), //
m(SingleRackVersionC.ChannelId.CLUSTER_RUN_STATE, new UnsignedWordElement(0x2113)), //
@@ -332,7 +327,7 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
.bit(14, SingleRackVersionC.ChannelId.LEVEL2_DISCHARGE_TEMP_HIGH) //
.bit(15, SingleRackVersionC.ChannelId.LEVEL2_DISCHARGE_TEMP_LOW) //
), //
- // Level 1 Alarm: EMS Control to stop charge, discharge, charge&discharge
+ // Level 1 Alarm: EMS Control to stop charge, discharge, charge&discharge
m(new BitsWordElement(0x2141, this) //
.bit(0, SingleRackVersionC.ChannelId.LEVEL1_CELL_VOLTAGE_HIGH) //
.bit(1, SingleRackVersionC.ChannelId.LEVEL1_TOTAL_VOLTAGE_HIGH) //
@@ -351,7 +346,7 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
.bit(14, SingleRackVersionC.ChannelId.LEVEL1_DISCHARGE_TEMP_HIGH) //
.bit(15, SingleRackVersionC.ChannelId.LEVEL1_DISCHARGE_TEMP_LOW) //
), //
- // Pre-Alarm: Temperature Alarm will active current limication
+ // Pre-Alarm: Temperature Alarm will active current limication
m(new BitsWordElement(0x2142, this) //
.bit(0, SingleRackVersionC.ChannelId.PRE_ALARM_CELL_VOLTAGE_HIGH) //
.bit(1, SingleRackVersionC.ChannelId.PRE_ALARM_TOTAL_VOLTAGE_HIGH) //
@@ -518,8 +513,7 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
new UnsignedWordElement(0x204B), ElementToChannelConverter.SCALE_FACTOR_2), //
m(SingleRackVersionC.ChannelId.LEVEL1_CELL_OVER_TEMPERATURE_PROTECTION,
new SignedWordElement(0x204C)), //
- m(SingleRackVersionC.ChannelId.LEVEL1_CELL_OVER_TEMPERATURE_RECOVER,
- new SignedWordElement(0x204D)), //
+ m(SingleRackVersionC.ChannelId.LEVEL1_CELL_OVER_TEMPERATURE_RECOVER, new SignedWordElement(0x204D)), //
m(SingleRackVersionC.ChannelId.LEVEL1_CELL_UNDER_TEMPERATURE_PROTECTION,
new SignedWordElement(0x204E)), //
m(SingleRackVersionC.ChannelId.LEVEL1_CELL_UNDER_TEMPERATURE_RECOVER,
@@ -592,8 +586,7 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
new UnsignedWordElement(0x240B), ElementToChannelConverter.SCALE_FACTOR_2), //
m(SingleRackVersionC.ChannelId.LEVEL2_CELL_OVER_TEMPERATURE_PROTECTION,
new SignedWordElement(0x240C)), //
- m(SingleRackVersionC.ChannelId.LEVEL2_CELL_OVER_TEMPERATURE_RECOVER,
- new SignedWordElement(0x240D)), //
+ m(SingleRackVersionC.ChannelId.LEVEL2_CELL_OVER_TEMPERATURE_RECOVER, new SignedWordElement(0x240D)), //
m(SingleRackVersionC.ChannelId.LEVEL2_CELL_UNDER_TEMPERATURE_PROTECTION,
new SignedWordElement(0x240E)), //
m(SingleRackVersionC.ChannelId.LEVEL2_CELL_UNDER_TEMPERATURE_RECOVER,
@@ -647,11 +640,11 @@ protected ModbusProtocol defineModbusProtocol() throws OpenemsException {
this.addChannel(channelId);
// Add the Modbus Element and map it to the Channel
if (type == Type.VOLTAGE) {
- elements[j] = m(channelId, new UnsignedWordElement(type.getOffset() + sensorIndex));
+ elements[j] = m(channelId, new UnsignedWordElement(type.getOffset() + sensorIndex));
} else {
elements[j] = m(channelId, new SignedWordElement(type.getOffset() + sensorIndex));
}
-
+
}
// Add a Modbus read task for this module
int startAddress = type.getOffset() + i * type.getSensorsPerModule();
diff --git a/io.openems.edge.batteryinverter.api/src/io/openems/edge/batteryinverter/api/HybridManagedSymmetricBatteryInverter.java b/io.openems.edge.batteryinverter.api/src/io/openems/edge/batteryinverter/api/HybridManagedSymmetricBatteryInverter.java
new file mode 100644
index 00000000000..7aa41525d63
--- /dev/null
+++ b/io.openems.edge.batteryinverter.api/src/io/openems/edge/batteryinverter/api/HybridManagedSymmetricBatteryInverter.java
@@ -0,0 +1,85 @@
+package io.openems.edge.batteryinverter.api;
+
+import org.osgi.annotation.versioning.ProviderType;
+
+import io.openems.common.channel.Unit;
+import io.openems.common.types.OpenemsType;
+import io.openems.edge.common.channel.Doc;
+import io.openems.edge.common.startstop.StartStoppable;
+import io.openems.edge.ess.api.HybridEss;
+import io.openems.edge.ess.dccharger.api.EssDcCharger;
+
+/**
+ * Represents a Hybrid Symmetric Battery-Inverter - as part of a
+ * {@link HybridEss} - that can be controlled.
+ */
+@ProviderType
+public interface HybridManagedSymmetricBatteryInverter
+ extends ManagedSymmetricBatteryInverter, SymmetricBatteryInverter, StartStoppable {
+
+ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
+ /**
+ * DC Discharge Power.
+ *
+ *
+ * - Interface: HybridManagedSymmetricBatteryInverter
+ *
- Type: Integer
+ *
- Unit: W
+ *
- Range: negative values for Charge; positive for Discharge
+ *
- This is the
+ * {@link io.openems.edge.ess.api.SymmetricBatteryInverter.ChannelId#ACTIVE_POWER}
+ * minus
+ * {@link io.openems.edge.ess.dccharger.api.EssDcCharger.ChannelId#ACTUAL_POWER},
+ * i.e. the power that is actually charged to or discharged from the battery.
+ *
+ */
+ DC_DISCHARGE_POWER(Doc.of(OpenemsType.INTEGER) //
+ .unit(Unit.WATT) //
+ .text(POWER_DOC_TEXT) //
+ ),
+ /**
+ * DC Charge Energy.
+ *
+ *
+ * - Interface: HybridEss
+ *
- Type: Long
+ *
- Unit: Wh
+ *
+ */
+ DC_CHARGE_ENERGY(Doc.of(OpenemsType.LONG) //
+ .unit(Unit.WATT_HOURS)),
+ /**
+ * DC Discharge Energy.
+ *
+ *
+ * - Interface: HybridEss
+ *
- Type: Long
+ *
- Unit: Wh
+ *
+ */
+ DC_DISCHARGE_ENERGY(Doc.of(OpenemsType.LONG) //
+ .unit(Unit.WATT_HOURS)),;
+
+ private final Doc doc;
+
+ private ChannelId(Doc doc) {
+ this.doc = doc;
+ }
+
+ public Doc doc() {
+ return this.doc;
+ }
+ }
+
+ /**
+ * Gets the Surplus Power of the {@link EssDcCharger}s of this
+ * {@link HybridManagedSymmetricBatteryInverter}.
+ *
+ *
+ * This value is usually calculated from the
+ * {@link EssDcCharger#getActualPower()} when the battery is full
+ *
+ * @return the surplus power, or 'null' if there is no surplus power
+ */
+ public Integer getSurplusPower();
+}
diff --git a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusWorker.java b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusWorker.java
index 1165942a310..57a2378bf15 100644
--- a/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusWorker.java
+++ b/io.openems.edge.bridge.modbus/src/io/openems/edge/bridge/modbus/api/ModbusWorker.java
@@ -167,6 +167,15 @@ public void onExecuteWrite() {
@Override
protected void forever() throws InterruptedException {
Task task = this.tasksQueue.takeLast();
+
+ // If there are no tasks in the bridge, there will always be only one
+ // 'WaitTask'.
+ if (task instanceof WaitTask && !this.hasTasks()) {
+ // Make sure to unset the 'SlaveCommunicationFailed' Status in that case.
+ this.parent._setSlaveCommunicationFailed(false);
+ return;
+ }
+
try {
// execute the task
int noOfExecutedSubTasks = task.execute(this.parent);
@@ -248,6 +257,15 @@ private List getAllWriteTasks() {
return this.filterDefectiveComponents(tasks);
}
+ /**
+ * Does this {@link ModbusWorker} have any Tasks?.
+ *
+ * @return true if there are Tasks
+ */
+ private boolean hasTasks() {
+ return this.writeTasksManager.hasTasks() && this.readTasksManager.hasTasks();
+ }
+
/**
* Filters a Multimap with Tasks by Component-ID. For Components that are known
* to be defective, only one task is added; otherwise all tasks are added to the
diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/Channel.java b/io.openems.edge.common/src/io/openems/edge/common/channel/Channel.java
index 9da11c47245..a87c8e6a81e 100644
--- a/io.openems.edge.common/src/io/openems/edge/common/channel/Channel.java
+++ b/io.openems.edge.common/src/io/openems/edge/common/channel/Channel.java
@@ -46,6 +46,13 @@
* @param the type of the Channel. One out of {@link OpenemsType}.
*/
public interface Channel {
+
+ /**
+ * Holds the number of past values for this Channel that are kept in the
+ * 'pastValues' variable.
+ */
+ public static final int NO_OF_PAST_VALUES = 300;
+
/**
* Gets the ChannelId of this Channel.
*
diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/Doc.java b/io.openems.edge.common/src/io/openems/edge/common/channel/Doc.java
index 2c2136d6660..bc5fababa1b 100644
--- a/io.openems.edge.common/src/io/openems/edge/common/channel/Doc.java
+++ b/io.openems.edge.common/src/io/openems/edge/common/channel/Doc.java
@@ -3,6 +3,7 @@
import io.openems.common.channel.AccessMode;
import io.openems.common.channel.ChannelCategory;
import io.openems.common.channel.Level;
+import io.openems.common.channel.PersistencePriority;
import io.openems.common.channel.Unit;
import io.openems.common.types.OpenemsType;
import io.openems.common.types.OptionsEnum;
@@ -106,6 +107,17 @@ public static StateChannelDoc of(Level level) {
*/
public Unit getUnit();
+ /**
+ * Gets the Persistence Priority. Defaults to VERY_LOW.
+ *
+ *
+ * This parameter may be used by persistence services to decide, if the Channel
+ * should be persisted to the hard disk.
+ *
+ * @return the {@link PersistencePriority}
+ */
+ public PersistencePriority getPersistencePriority();
+
/**
* Sets the descriptive text. Defaults to an empty string.
*
diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractDoc.java b/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractDoc.java
index a171a31fb1a..5e3664bf31d 100644
--- a/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractDoc.java
+++ b/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractDoc.java
@@ -5,6 +5,7 @@
import java.util.function.Consumer;
import io.openems.common.channel.AccessMode;
+import io.openems.common.channel.PersistencePriority;
import io.openems.common.channel.Unit;
import io.openems.common.types.OpenemsType;
import io.openems.edge.common.channel.Channel;
@@ -58,6 +59,30 @@ public AccessMode getAccessMode() {
return this.accessMode;
}
+ /**
+ * PersistencePriority for this Channel.
+ */
+ private PersistencePriority persistencePriority = PersistencePriority.VERY_LOW;
+
+ /**
+ * Sets the Persistence Priority. Defaults to VERY_LOW.
+ *
+ *
+ * This parameter may be used by persistence services to decide, if the Channel
+ * should be persisted to the hard disk.
+ *
+ * @param persistencePriority the {@link PersistencePriority}
+ */
+ public AbstractDoc persistencePriority(PersistencePriority persistencePriority) {
+ this.persistencePriority = persistencePriority;
+ return this.self();
+ }
+
+ @Override
+ public PersistencePriority getPersistencePriority() {
+ return this.persistencePriority;
+ }
+
/*
* Initial Value
*/
diff --git a/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractReadChannel.java b/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractReadChannel.java
index 6e7a388a83f..707e02eaf0c 100644
--- a/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractReadChannel.java
+++ b/io.openems.edge.common/src/io/openems/edge/common/channel/internal/AbstractReadChannel.java
@@ -23,12 +23,6 @@
public abstract class AbstractReadChannel, T> implements Channel {
- /**
- * Holds the number of past values for this Channel that are kept in the
- * 'pastValues' variable.
- */
- public static final int NO_OF_PAST_VALUES = 100;
-
private final Logger log = LoggerFactory.getLogger(AbstractReadChannel.class);
protected final OpenemsComponent parent;
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 1b3563fb069..a45aac48fab 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
@@ -15,6 +15,7 @@
import com.google.common.base.CaseFormat;
+import io.openems.common.channel.PersistencePriority;
import io.openems.common.exceptions.OpenemsException;
import io.openems.common.types.EdgeConfig;
import io.openems.common.types.OptionsEnum;
@@ -238,7 +239,8 @@ private void addChannelsForProperties(ComponentContext context) {
.get(io.openems.edge.common.channel.ChannelId.channelIdUpperToCamel(channelName));
if (channel == null) {
// Channel does not already exist -> create new Channel
- Doc doc = AbstractOpenemsComponent.getDocFromObject(value);
+ AbstractDoc> doc = AbstractOpenemsComponent.getDocFromObject(value);
+ doc.persistencePriority(PersistencePriority.MEDIUM);
io.openems.edge.common.channel.ChannelId channelId = new io.openems.edge.common.channel.ChannelId() {
@Override
diff --git a/io.openems.edge.common/src/io/openems/edge/common/component/ClockProvider.java b/io.openems.edge.common/src/io/openems/edge/common/component/ClockProvider.java
index 25e1855fe01..ba23da44d2f 100644
--- a/io.openems.edge.common/src/io/openems/edge/common/component/ClockProvider.java
+++ b/io.openems.edge.common/src/io/openems/edge/common/component/ClockProvider.java
@@ -2,8 +2,6 @@
import java.time.Clock;
-import io.openems.edge.common.test.TimeLeapClock;
-
/**
* {@link ClockProvider} provides a Clock - real or mocked like
* {@link TimeLeapClock}.
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 c431421dfa1..7836ad0c69a 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
@@ -12,6 +12,7 @@
import io.openems.common.channel.AccessMode;
import io.openems.common.channel.Level;
+import io.openems.common.channel.PersistencePriority;
import io.openems.common.utils.ConfigUtils;
import io.openems.edge.common.channel.Channel;
import io.openems.edge.common.channel.Doc;
@@ -182,7 +183,8 @@ default > T channel(io.openems.edge.common.channel.ChannelI
public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
// Running State of the component. Keep values in sync with 'Level' enum!
- STATE(new StateCollectorChannelDoc());
+ STATE(new StateCollectorChannelDoc() //
+ .persistencePriority(PersistencePriority.VERY_HIGH));
private final Doc doc;
diff --git a/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java b/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java
index 74232f63620..e9075cd5f3b 100644
--- a/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java
+++ b/io.openems.edge.common/src/io/openems/edge/common/sum/Sum.java
@@ -2,6 +2,7 @@
import io.openems.common.OpenemsConstants;
import io.openems.common.channel.AccessMode;
+import io.openems.common.channel.PersistencePriority;
import io.openems.common.channel.Unit;
import io.openems.common.types.OpenemsType;
import io.openems.edge.common.channel.Channel;
@@ -30,7 +31,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
ESS_SOC(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.PERCENT)),
+ .unit(Unit.PERCENT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)),
/**
* Ess: Active Power.
*
@@ -43,6 +45,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
ESS_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH) //
.text(OpenemsConstants.POWER_DOC_TEXT)),
/**
* Reactive Power.
@@ -56,6 +59,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
ESS_REACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.VOLT_AMPERE_REACTIVE) //
+ .persistencePriority(PersistencePriority.VERY_HIGH) //
.text(OpenemsConstants.POWER_DOC_TEXT) //
),
/**
@@ -70,6 +74,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
ESS_ACTIVE_POWER_L1(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH) //
.text(OpenemsConstants.POWER_DOC_TEXT)),
/**
* Ess: Active Power L2.
@@ -83,6 +88,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
ESS_ACTIVE_POWER_L2(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH) //
.text(OpenemsConstants.POWER_DOC_TEXT)),
/**
* Ess: Active Power L3.
@@ -96,6 +102,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
ESS_ACTIVE_POWER_L3(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH) //
.text(OpenemsConstants.POWER_DOC_TEXT)),
/**
* Ess: Discharge Power.
@@ -114,6 +121,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
ESS_DISCHARGE_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH) //
.text(OpenemsConstants.POWER_DOC_TEXT)),
/**
* Ess: Capacity.
@@ -126,7 +134,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
ESS_CAPACITY(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT_HOURS)), //
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Grid: Active Power.
@@ -142,6 +151,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
GRID_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH) //
.text(OpenemsConstants.POWER_DOC_TEXT)),
/**
* Grid: Active Power L1.
@@ -157,6 +167,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
GRID_ACTIVE_POWER_L1(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH) //
.text(OpenemsConstants.POWER_DOC_TEXT)),
/**
* Grid: Active Power L2.
@@ -172,6 +183,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
GRID_ACTIVE_POWER_L2(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH) //
.text(OpenemsConstants.POWER_DOC_TEXT)),
/**
* Grid: Active Power L3.
@@ -187,6 +199,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
GRID_ACTIVE_POWER_L3(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH) //
.text(OpenemsConstants.POWER_DOC_TEXT)),
/**
* Grid: Minimum Ever Active Power.
@@ -199,7 +212,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
GRID_MIN_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)),
/**
* Grid: Maximum Ever Active Power.
*
@@ -211,7 +225,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
GRID_MAX_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)),
/**
* Production: Active Power.
*
@@ -223,7 +238,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
PRODUCTION_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production: AC Active Power.
*
@@ -235,7 +251,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
PRODUCTION_AC_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production: AC Active Power L1.
*
@@ -247,7 +264,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
PRODUCTION_AC_ACTIVE_POWER_L1(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production: AC Active Power L2.
*
@@ -259,7 +277,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
PRODUCTION_AC_ACTIVE_POWER_L2(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production: AC Active Power L3.
*
@@ -271,7 +290,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
PRODUCTION_AC_ACTIVE_POWER_L3(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production: DC Actual Power.
*
@@ -283,7 +303,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
PRODUCTION_DC_ACTUAL_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production: Maximum Ever Active Power.
*
@@ -295,7 +316,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
PRODUCTION_MAX_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production: Maximum Ever AC Active Power.
*
@@ -307,7 +329,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
PRODUCTION_MAX_AC_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production: Maximum Ever DC Actual Power.
*
@@ -319,7 +342,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
PRODUCTION_MAX_DC_ACTUAL_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Consumption: Active Power.
*
@@ -333,7 +357,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
CONSUMPTION_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Consumption: Active Power L1.
*
@@ -347,7 +372,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
CONSUMPTION_ACTIVE_POWER_L1(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Consumption: Active Power L2.
*
@@ -361,7 +387,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
CONSUMPTION_ACTIVE_POWER_L2(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Consumption: Active Power L3.
*
@@ -375,7 +402,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
CONSUMPTION_ACTIVE_POWER_L3(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Consumption: Maximum Ever Active Power.
*
@@ -387,7 +415,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
CONSUMPTION_MAX_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)),
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Grid-Mode.
*
@@ -397,7 +426,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
* Values: '0' = UNDEFINED, '1' = ON GRID, '2' = OFF GRID
*
*/
- GRID_MODE(Doc.of(GridMode.values())),
+ GRID_MODE(Doc.of(GridMode.values()) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Ess: Max Apparent Power.
@@ -409,7 +439,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
ESS_MAX_APPARENT_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.VOLT_AMPERE)),
+ .unit(Unit.VOLT_AMPERE) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Ess: Active Charge Energy.
*
@@ -420,7 +451,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
ESS_ACTIVE_CHARGE_ENERGY(Doc.of(OpenemsType.LONG) //
- .unit(Unit.WATT_HOURS)),
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Ess: Active Discharge Energy.
*
@@ -431,7 +463,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
ESS_ACTIVE_DISCHARGE_ENERGY(Doc.of(OpenemsType.LONG) //
- .unit(Unit.WATT_HOURS)),
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Ess: DC Discharge Energy.
*
@@ -442,7 +475,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
ESS_DC_DISCHARGE_ENERGY(Doc.of(OpenemsType.LONG) //
- .unit(Unit.WATT_HOURS)), //
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Ess: DC Charge Energy.
*
@@ -453,7 +487,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
ESS_DC_CHARGE_ENERGY(Doc.of(OpenemsType.LONG) //
- .unit(Unit.WATT_HOURS)), //
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Grid: Buy-from-grid Energy ("Production").
*
@@ -464,7 +499,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
GRID_BUY_ACTIVE_ENERGY(Doc.of(OpenemsType.LONG) //
- .unit(Unit.WATT_HOURS)),
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Grid: Sell-to-grid Energy ("Consumption").
*
@@ -475,7 +511,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
GRID_SELL_ACTIVE_ENERGY(Doc.of(OpenemsType.LONG) //
- .unit(Unit.WATT_HOURS)),
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production: Energy.
*
@@ -485,7 +522,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
PRODUCTION_ACTIVE_ENERGY(Doc.of(OpenemsType.LONG) //
- .unit(Unit.WATT_HOURS)),
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production: AC Energy.
*
@@ -496,7 +534,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
PRODUCTION_AC_ACTIVE_ENERGY(Doc.of(OpenemsType.LONG) //
- .unit(Unit.WATT_HOURS)),
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Production: DC Energy.
*
@@ -508,7 +547,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
// TODO rename to Actual_Energy
PRODUCTION_DC_ACTIVE_ENERGY(Doc.of(OpenemsType.LONG) //
- .unit(Unit.WATT_HOURS)),
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
/**
* Consumption: Energy.
*
@@ -519,7 +559,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
CONSUMPTION_ACTIVE_ENERGY(Doc.of(OpenemsType.LONG) //
- .unit(Unit.WATT_HOURS));
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.VERY_HIGH));
private final Doc doc;
@@ -546,8 +587,8 @@ public static ModbusSlaveNatureTable getModbusSlaveNatureTable(AccessMode access
.channel(0, ChannelId.ESS_SOC, ModbusType.UINT16) //
.channel(1, ChannelId.ESS_ACTIVE_POWER, ModbusType.FLOAT32) //
.float32Reserved(3) // ChannelId.ESS_MIN_ACTIVE_POWER
- .float32Reserved(5) // ChannelId.ESS_MAX_ACTIVE_POWER
- .channel(7, ChannelId.ESS_REACTIVE_POWER, ModbusType.FLOAT32) //ESS_REACTIVE_POWER
+ .float32Reserved(5) // ChannelId.ESS_MAX_ACTIVE_POWER
+ .channel(7, ChannelId.ESS_REACTIVE_POWER, ModbusType.FLOAT32) // ESS_REACTIVE_POWER
.float32Reserved(9) // ChannelId.ESS_MIN_REACTIVE_POWER
.float32Reserved(11) // ChannelId.ESS_MAX_REACTIVE_POWER
.channel(13, ChannelId.GRID_ACTIVE_POWER, ModbusType.FLOAT32) //
@@ -669,7 +710,7 @@ public default void _setEssActivePower(Integer value) {
public default void _setEssActivePower(int value) {
this.getEssActivePowerChannel().setNextValue(value);
}
-
+
/**
* Gets the Channel for {@link ChannelId#ESS_REACTIVE_POWER}.
*
@@ -680,7 +721,7 @@ public default IntegerReadChannel getEssReactivePowerChannel() {
}
/**
- * Gets the Sum of all Energy Storage System Reactive Power in [var].
+ * Gets the Sum of all Energy Storage System Reactive Power in [var].
* {@link ChannelId#ESS_REACTIVE_POWER}.
*
* @return the Channel {@link Value}
@@ -690,8 +731,8 @@ public default Value getEssReactivePower() {
}
/**
- * Internal method to set the 'nextValue' on {@link ChannelId#ESS_REACTIVE_POWER}
- * Channel.
+ * Internal method to set the 'nextValue' on
+ * {@link ChannelId#ESS_REACTIVE_POWER} Channel.
*
* @param value the next value
*/
diff --git a/io.openems.edge.common/src/io/openems/edge/common/taskmanager/MetaTasksManager.java b/io.openems.edge.common/src/io/openems/edge/common/taskmanager/MetaTasksManager.java
index 0b6b63ed73e..3b85c4ef5d6 100644
--- a/io.openems.edge.common/src/io/openems/edge/common/taskmanager/MetaTasksManager.java
+++ b/io.openems.edge.common/src/io/openems/edge/common/taskmanager/MetaTasksManager.java
@@ -109,4 +109,13 @@ public Multimap getAllTasksBySourceId() {
return result;
}
+ /**
+ * Does this {@link TasksManager} have any Tasks?.
+ *
+ * @return true if there are Tasks
+ */
+ public boolean hasTasks() {
+ return !this.tasksManagers.isEmpty();
+ }
+
}
\ No newline at end of file
diff --git a/io.openems.edge.common/src/io/openems/edge/common/type/TypeUtils.java b/io.openems.edge.common/src/io/openems/edge/common/type/TypeUtils.java
index 5f725ee0d8b..942a9b101ac 100644
--- a/io.openems.edge.common/src/io/openems/edge/common/type/TypeUtils.java
+++ b/io.openems.edge.common/src/io/openems/edge/common/type/TypeUtils.java
@@ -585,7 +585,24 @@ public static Integer averageRounded(Integer... values) {
}
/**
- * Throws a descriptive exception if any of the objects is null.
+ * Safely finds the min value of all values.
+ *
+ * @return the min value; or null if all values are null
+ */
+ public static Integer min(Integer... values) {
+ Integer result = null;
+ for (Integer value : values) {
+ if (result != null && value != null) {
+ result = Math.min(result, value);
+ } else if (value != null) {
+ result = value;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Throws an descriptive exception if the object is null.
*
* @param description text that is added to the exception
* @param objects the objects
diff --git a/io.openems.edge.common/test/io/openems/edge/common/type/TypeUtilsTest.java b/io.openems.edge.common/test/io/openems/edge/common/type/TypeUtilsTest.java
index e7b35ac3957..ed60fdc7ba0 100644
--- a/io.openems.edge.common/test/io/openems/edge/common/type/TypeUtilsTest.java
+++ b/io.openems.edge.common/test/io/openems/edge/common/type/TypeUtilsTest.java
@@ -1,6 +1,6 @@
package io.openems.edge.common.type;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
import org.junit.Test;
@@ -39,4 +39,12 @@ public void testAverageRounded() {
assertEquals(Integer.valueOf(3), TypeUtils.averageRounded(2, null, 3));
}
+ @Test
+ public void testMin() {
+ assertEquals(25, (int) TypeUtils.min(null, 25, null, 40, null));
+ assertEquals(null, TypeUtils.min((Double) null, null, null));
+ assertEquals(17, (int) TypeUtils.min(null, 17, 25, 40));
+ assertEquals(34, (int) TypeUtils.min(null, 34, 40));
+ }
+
}
diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendApi.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendApi.java
index a7b836e1067..2cbebcd29e1 100644
--- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendApi.java
+++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendApi.java
@@ -3,8 +3,11 @@
import org.ops4j.pax.logging.spi.PaxAppender;
import org.osgi.service.event.EventHandler;
+import io.openems.common.channel.Level;
+import io.openems.common.channel.PersistencePriority;
import io.openems.common.types.OpenemsType;
import io.openems.edge.common.channel.Doc;
+import io.openems.edge.common.channel.StateChannel;
import io.openems.edge.common.channel.StringReadChannel;
import io.openems.edge.common.component.OpenemsComponent;
import io.openems.edge.controller.api.Controller;
@@ -13,7 +16,16 @@ public interface BackendApi extends Controller, OpenemsComponent, PaxAppender, E
public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
API_WORKER_LOG(Doc.of(OpenemsType.STRING) //
- .text("Logs Write-Commands via ApiWorker")); //
+ .text("Logs Write-Commands via ApiWorker")), //
+ UNABLE_TO_SEND(Doc.of(Level.WARNING)
+ // Make sure this is always persisted, as it is required for resending
+ .persistencePriority(PersistencePriority.VERY_HIGH)), //
+ LAST_SUCCESSFUL_RESEND(Doc.of(OpenemsType.LONG) //
+ // Make sure this is always persisted, as it is required for resending
+ .persistencePriority(PersistencePriority.VERY_HIGH) //
+ .text("Latest timestamp of successfully resent data")) //
+ // TODO: resend algorithm still needs to be implemented
+ ;
private final Doc doc;
@@ -35,4 +47,13 @@ public Doc doc() {
public default StringReadChannel getApiWorkerLogChannel() {
return this.channel(ChannelId.API_WORKER_LOG);
}
+
+ /**
+ * Gets the Channel for {@link ChannelId#UNABLE_TO_SEND}.
+ *
+ * @return the Channel
+ */
+ public default StateChannel getUnableToSendChannel() {
+ return this.channel(ChannelId.UNABLE_TO_SEND);
+ }
}
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 1374d6ed00d..875ed6a5e36 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
@@ -33,6 +33,7 @@
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.common.cycle.Cycle;
import io.openems.edge.common.event.EdgeEventConstants;
import io.openems.edge.controller.api.Controller;
import io.openems.edge.controller.api.common.ApiWorker;
@@ -51,18 +52,16 @@
public class BackendApiImpl extends AbstractOpenemsComponent
implements BackendApi, Controller, OpenemsComponent, PaxAppender, EventHandler {
- protected static final int DEFAULT_NO_OF_CYCLES = 10;
protected static final String COMPONENT_NAME = "Controller.Api.Backend";
- protected final BackendWorker worker = new BackendWorker(this);
+ protected final SendChannelValuesWorker sendChannelValuesWorker = new SendChannelValuesWorker(this);
protected final ApiWorker apiWorker = new ApiWorker(this);
private final Logger log = LoggerFactory.getLogger(BackendApiImpl.class);
protected WebsocketClient websocket = null;
- protected int noOfCycles = DEFAULT_NO_OF_CYCLES; // default, is going to be overwritten by config
- protected boolean debug = false;
+ protected Config config;
// Used for SubscribeSystemLogRequests
private boolean isSystemLogSubscribed = false;
@@ -73,6 +72,9 @@ public class BackendApiImpl extends AbstractOpenemsComponent
@Reference
protected ComponentManager componentManager;
+ @Reference
+ protected Cycle cycle;
+
public BackendApiImpl() {
super(//
OpenemsComponent.ChannelId.values(), //
@@ -84,9 +86,8 @@ public BackendApiImpl() {
@Activate
void activate(ComponentContext context, Config config) {
+ this.config = config;
super.activate(context, config.id(), config.alias(), config.enabled());
- this.noOfCycles = config.noOfCycles();
- this.debug = config.debug();
if (!this.isEnabled()) {
return;
@@ -119,15 +120,12 @@ void activate(ComponentContext context, Config config) {
// Create Websocket instance
this.websocket = new WebsocketClient(this, COMPONENT_NAME + ":" + this.id(), uri, httpHeaders, proxy);
this.websocket.start();
-
- // Activate worker
- this.worker.activate(config.id());
}
@Deactivate
protected void deactivate() {
super.deactivate();
- this.worker.deactivate();
+ this.sendChannelValuesWorker.deactivate();
if (this.websocket != null) {
this.websocket.stop();
}
@@ -181,10 +179,11 @@ public void handleEvent(Event event) {
}
switch (event.getTopic()) {
case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE:
- this.worker.triggerNextRun();
+ this.sendChannelValuesWorker.collectData();
break;
case EdgeEventConstants.TOPIC_CONFIG_UPDATE:
+ // Send new EdgeConfig
EdgeConfig config = (EdgeConfig) event.getProperty(EdgeEventConstants.TOPIC_CONFIG_UPDATE_KEY);
EdgeConfigNotification message = new EdgeConfigNotification(config);
WebsocketClient ws = this.websocket;
@@ -192,6 +191,14 @@ public void handleEvent(Event event) {
return;
}
ws.sendMessage(message);
+
+ // Trigger sending of all channel values, because a Component might have
+ // disappeared
+ this.sendChannelValuesWorker.sendValuesOfAllChannelsOnce();
}
}
+
+ public boolean isConnected() {
+ return this.websocket.isConnected();
+ }
}
diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendWorker.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendWorker.java
index c0b2c2c3247..be5ac5e371f 100644
--- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendWorker.java
+++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/BackendWorker.java
@@ -1,261 +1,177 @@
package io.openems.edge.controller.api.backend;
+import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
-import java.util.Iterator;
+import java.util.List;
import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
-import com.google.common.collect.EvictingQueue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableTable;
import com.google.gson.JsonElement;
+import com.google.gson.JsonNull;
import io.openems.common.channel.AccessMode;
-import io.openems.common.jsonrpc.base.JsonrpcMessage;
import io.openems.common.jsonrpc.notification.TimestampedDataNotification;
import io.openems.common.types.ChannelAddress;
-import io.openems.common.types.OpenemsType;
-import io.openems.common.worker.AbstractCycleWorker;
-import io.openems.edge.common.channel.EnumReadChannel;
-import io.openems.edge.common.type.slidingvalue.DoubleSlidingValue;
-import io.openems.edge.common.type.slidingvalue.FloatSlidingValue;
-import io.openems.edge.common.type.slidingvalue.IntegerSlidingValue;
-import io.openems.edge.common.type.slidingvalue.LatestSlidingValue;
-import io.openems.edge.common.type.slidingvalue.LongSlidingValue;
-import io.openems.edge.common.type.slidingvalue.ShortSlidingValue;
-import io.openems.edge.common.type.slidingvalue.SlidingValue;
-
-class BackendWorker extends AbstractCycleWorker {
+import io.openems.edge.common.component.OpenemsComponent;
- private static final int MAX_CACHED_MESSAGES = 1000;
+public class BackendWorker {
- // private final Logger log = LoggerFactory.getLogger(BackendWorker.class);
+ private static final int SEND_VALUES_OF_ALL_CHANNELS_AFTER_SECONDS = 300; /* 5 minutes */
+ private final Logger log = LoggerFactory.getLogger(BackendWorker.class);
private final BackendApiImpl parent;
+ private final ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.SECONDS,
+ new ArrayBlockingQueue<>(1), new ThreadPoolExecutor.DiscardOldestPolicy());
- // Counts the number of Cycles till data is sent to Backend.
- private int cycleCount = 0;
-
- // Holds an current NoOfCycles
- private Optional increasedNoOfCycles = Optional.empty();
-
- // Current values
- private final ConcurrentHashMap> data = new ConcurrentHashMap<>();
+ // Component-ID to Channel-ID to value
+ private ImmutableTable lastValues = ImmutableTable.of();
- // Unsent queue (FIFO)
- private EvictingQueue unsent = EvictingQueue.create(MAX_CACHED_MESSAGES);
-
- // By default the worker reads and sends only changed values. If this variable
- // is set to 'false', it sends all values once.
- private final AtomicBoolean sendChangedValuesOnly = new AtomicBoolean(false);
+ private Instant lastSendValuesOfAllChannels = Instant.MIN;
protected BackendWorker(BackendApiImpl parent) {
this.parent = parent;
}
- @Override
- public void activate(String name) {
- super.activate(name);
- }
-
- @Override
- public void deactivate() {
- super.deactivate();
- }
-
/**
- * Triggers sending all Channel values once. After executing once, this is reset
- * automatically to default 'send changed values only' mode.
+ * Called synchronously on AFTER_PROCESS_IMAGE event. Collects all the data and
+ * triggers asynchronous sending.
*/
- public void sendValuesOfAllChannelsOnce() {
- this.sendChangedValuesOnly.set(false);
- this.triggerNextRun();
- }
+ public synchronized void collectData() {
+ Instant now = Instant.now(this.parent.componentManager.getClock());
- @Override
- protected void forever() {
- // Update the data from ChannelValues
- this.updateData();
-
- // Increase CycleCount
- if (++this.cycleCount < this.parent.noOfCycles) {
- // Stop here if not reached CycleCount
- return;
+ // Send values of all Channels once in a while
+ if (Duration.between(this.lastSendValuesOfAllChannels, now)
+ .getSeconds() > SEND_VALUES_OF_ALL_CHANNELS_AFTER_SECONDS) {
+ this.lastValues = ImmutableTable.of();
}
+ if (this.lastValues.isEmpty()) {
+ this.lastSendValuesOfAllChannels = now;
+ }
+
+ final List enabledComponents = this.parent.componentManager.getEnabledComponents();
- /*
- * Reached CycleCount -> Send data
- */
- // Reset CycleCount
- this.cycleCount = 0;
+ // Update the data from ChannelValues
+ final ImmutableTable allValues = this.collectData(enabledComponents);
- // resets the mode to 'send changed values only'
- boolean sendChangedValuesOnly = this.sendChangedValuesOnly.getAndSet(true);
+ // Get timestamp and round to Global Cycle-Time
+ final int cycleTime = this.parent.cycle.getCycleTime();
+ final long timestamp = now.toEpochMilli() / cycleTime * cycleTime;
// Prepare message values
Map sendValues = new HashMap<>();
- if (sendChangedValuesOnly) {
- // Only Changed Values
- for (Entry> entry : this.data.entrySet()) {
- JsonElement changedValueOrNull = entry.getValue().getChangedValueOrNull();
- if (changedValueOrNull != null) {
- sendValues.put(entry.getKey(), changedValueOrNull);
- }
- }
- } else {
- // All Values
- for (Entry> entry : this.data.entrySet()) {
- sendValues.put(entry.getKey(), entry.getValue().getValue());
- }
- }
-
- boolean canSendFromCache;
+ // Collect Changed values
+ allValues.rowMap().entrySet().parallelStream() //
+ .forEach(row -> {
+ row.getValue().entrySet().parallelStream() //
+ .forEach(column -> {
+ if (!Objects.equals(column.getValue(),
+ this.lastValues.get(row.getKey(), column.getKey()))) {
+ sendValues.put(new ChannelAddress(row.getKey(), column.getKey()),
+ column.getValue());
+ }
+ });
+ });
- /*
- * send, if list is not empty
- */
- if (!sendValues.isEmpty()) {
- // Get timestamp and round to Cycle-Time
- int cycleTime = this.getCycleTime();
- long timestamp = Instant.now(this.parent.componentManager.getClock()).toEpochMilli() / cycleTime
- * cycleTime;
+ // Update disappeared components
+ final Set enabledComponentIds = enabledComponents.stream() //
+ .map(c -> c.id()) //
+ .collect(Collectors.toSet());
+ this.lastValues.rowMap().entrySet().stream() //
+ .filter(row -> !enabledComponentIds.contains(row.getKey())) //
+ .forEach(row -> {
+ row.getValue().entrySet().parallelStream() //
+ .forEach(column -> {
+ sendValues.put(new ChannelAddress(row.getKey(), column.getKey()), JsonNull.INSTANCE);
+ });
+ });
- // create JSON-RPC notification
- TimestampedDataNotification message = new TimestampedDataNotification();
- message.add(timestamp, sendValues);
+ // Keep values for next run
+ this.lastValues = allValues;
- // reset cycleTime to default
- this.resetNoOfCycles();
+ // Nothing to send
+ if (sendValues.isEmpty()) {
+ return;
+ }
- boolean wasSent = this.parent.websocket.sendMessage(message);
- if (!wasSent) {
- // increase cycleTime
- this.increaseNoOfCycles();
+ // create JSON-RPC notification
+ TimestampedDataNotification message = new TimestampedDataNotification();
+ message.add(timestamp, sendValues);
- // cache data for later
- this.unsent.add(message);
- }
+ // Add to Task Queue
+ this.executor.execute(new SendTask(this, message));
+ }
- canSendFromCache = wasSent;
- } else {
- canSendFromCache = true;
- }
+ /**
+ * Triggers sending all Channel values once. After executing once, this is reset
+ * automatically to default 'send changed values only' mode.
+ */
+ public synchronized void sendValuesOfAllChannelsOnce() {
+ this.lastValues = ImmutableTable.of();
+ }
- // send from cache
- if (canSendFromCache && !this.unsent.isEmpty()) {
- for (Iterator iterator = this.unsent.iterator(); iterator.hasNext();) {
- JsonrpcMessage cached = iterator.next();
- boolean cacheWasSent = this.parent.websocket.sendMessage(cached);
- if (cacheWasSent) {
- // sent successfully -> remove from cache & try next
- iterator.remove();
+ public void deactivate() {
+ // Shutdown executor
+ if (this.executor != null) {
+ try {
+ this.executor.shutdown();
+ this.executor.awaitTermination(5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ this.log.warn("tasks interrupted");
+ } finally {
+ if (!this.executor.isTerminated()) {
+ this.log.warn("cancel non-finished tasks");
}
+ this.executor.shutdownNow();
}
}
}
/**
- * Cycles through all Channels and updates the value.
+ * Cycles through all Channels and collects the value.
+ *
+ * @param enabledComponents the enabled components
+ * @return collected data
*/
- private void updateData() {
- this.parent.componentManager.getEnabledComponents().parallelStream() //
- .filter(c -> c.isEnabled()) //
+ private ImmutableTable collectData(List enabledComponents) {
+ return enabledComponents.parallelStream() //
.flatMap(component -> component.channels().parallelStream()) //
.filter(channel -> // Ignore WRITE_ONLY Channels
channel.channelDoc().getAccessMode() == AccessMode.READ_ONLY
|| channel.channelDoc().getAccessMode() == AccessMode.READ_WRITE)
- .forEach(channel -> {
- ChannelAddress address = channel.address();
- Object value = channel.value().get();
-
- // Get existing SlidingValue object or add new one
- SlidingValue> slidingValue = this.data.get(address);
+ .collect(ImmutableTable.toImmutableTable(c -> c.address().getComponentId(),
+ c -> c.address().getChannelId(), c -> c.value().asJson()));
+ }
- if (slidingValue == null) {
- // Create new SlidingValue object
- if (channel instanceof EnumReadChannel) {
- slidingValue = new LatestSlidingValue(OpenemsType.INTEGER);
- } else {
- switch (channel.getType()) {
- case INTEGER:
- slidingValue = new IntegerSlidingValue();
- break;
- case DOUBLE:
- slidingValue = new DoubleSlidingValue();
- break;
- case FLOAT:
- slidingValue = new FloatSlidingValue();
- break;
- case LONG:
- slidingValue = new LongSlidingValue();
- break;
- case SHORT:
- slidingValue = new ShortSlidingValue();
- break;
- case BOOLEAN:
- case STRING:
- slidingValue = new LatestSlidingValue(channel.getType());
- break;
- }
- }
- this.data.put(address, slidingValue);
- }
+ private static class SendTask implements Runnable {
- // Add Value to SlidingValue object
- if (slidingValue instanceof LatestSlidingValue) {
- ((LatestSlidingValue) slidingValue).addValue(value);
- } else {
- switch (channel.getType()) {
- case INTEGER:
- ((IntegerSlidingValue) slidingValue).addValue((Integer) value);
- break;
- case DOUBLE:
- ((DoubleSlidingValue) slidingValue).addValue((Double) value);
- break;
- case FLOAT:
- ((FloatSlidingValue) slidingValue).addValue((Float) value);
- break;
- case LONG:
- ((LongSlidingValue) slidingValue).addValue((Long) value);
- break;
- case SHORT:
- ((ShortSlidingValue) slidingValue).addValue((Short) value);
- break;
- case BOOLEAN:
- case STRING:
- // already covered as they are of type LatestSlidingValue
- break;
- }
- }
- });
- }
+ private final BackendWorker parent;
+ private final TimestampedDataNotification message;
- /**
- * NoOfCycles is adjusted if connection to Backend fails. This method increases
- * the NoOfCycles.
- */
- private void increaseNoOfCycles() {
- int increasedNoOfCycles;
- if (this.increasedNoOfCycles.isPresent()) {
- increasedNoOfCycles = this.increasedNoOfCycles.get();
- } else {
- increasedNoOfCycles = this.parent.noOfCycles;
- }
- if (increasedNoOfCycles < 60) {
- increasedNoOfCycles++;
+ public SendTask(BackendWorker parent, TimestampedDataNotification message) {
+ this.parent = parent;
+ this.message = message;
}
- this.increasedNoOfCycles = Optional.of(increasedNoOfCycles);
- }
- /**
- * NoOfCycles is adjusted if connection to Backend fails. This method resets it
- * to configured or default value.
- */
- private void resetNoOfCycles() {
- this.increasedNoOfCycles = Optional.empty();
- }
+ @Override
+ public void run() {
+ // Try to send; drop message if not possible to send (i.e. task is not
+ // rescheduled)
+ boolean wasSent = this.parent.parent.websocket.sendMessage(this.message);
+
+ // Set the UNABLE_TO_SEND channel
+ this.parent.parent.getUnableToSendChannel().setNextValue(!wasSent);
+ }
-}
\ No newline at end of file
+ };
+}
diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/Config.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/Config.java
index b0bb8ea5686..df7a64e63a9 100644
--- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/Config.java
+++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/Config.java
@@ -6,6 +6,8 @@
import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+import io.openems.common.channel.PersistencePriority;
+
@ObjectClassDefinition(//
name = "Controller Api Backend", //
description = "This controller connects to OpenEMS Backend")
@@ -26,9 +28,6 @@
@AttributeDefinition(name = "Uri", description = "The connection Uri to OpenEMS Backend.")
String uri() default "ws://localhost:8081";
- @AttributeDefinition(name = "No. of Cycles", description = "How many Cycles till data is sent to OpenEMS Backend.")
- int noOfCycles() default BackendApiImpl.DEFAULT_NO_OF_CYCLES;
-
@AttributeDefinition(name = "Proxy Address", description = "The IP address or hostname of the proxy server.")
String proxyAddress() default "";
@@ -41,8 +40,11 @@
@AttributeDefinition(name = "Api-Timeout", description = "Sets the timeout in seconds for updates on Channels set by this Api.")
int apiTimeout() default 60;
- @AttributeDefinition(name = "Enable Debug mode")
- boolean debug() default false;
+ @AttributeDefinition(name = "Persistence Priority", description = "Send only Channels with a Persistence Priority greater-or-equals this.")
+ PersistencePriority persistencePriority() default PersistencePriority.VERY_LOW;
+
+ @AttributeDefinition(name = "Debug Mode", description = "Activates the debug mode")
+ boolean debugMode() default false;
String webconsole_configurationFactory_nameHint() default "Controller Api Backend [{id}]";
}
\ No newline at end of file
diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnOpen.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnOpen.java
index 6ff3fb507d0..424262dd01b 100644
--- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnOpen.java
+++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/OnOpen.java
@@ -28,7 +28,7 @@ public void run(WebSocket ws, JsonObject handshake) {
this.parent.websocket.sendMessage(message);
// Send all Channel values
- this.parent.worker.sendValuesOfAllChannelsOnce();
+ this.parent.sendChannelValuesWorker.sendValuesOfAllChannelsOnce();
}
}
diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/SendChannelValuesWorker.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/SendChannelValuesWorker.java
new file mode 100644
index 00000000000..217148b8f11
--- /dev/null
+++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/SendChannelValuesWorker.java
@@ -0,0 +1,210 @@
+package io.openems.edge.controller.api.backend;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableTable;
+import com.google.common.collect.Table;
+import com.google.gson.JsonElement;
+
+import io.openems.common.channel.AccessMode;
+import io.openems.common.jsonrpc.notification.TimestampedDataNotification;
+import io.openems.common.types.ChannelAddress;
+import io.openems.edge.common.component.OpenemsComponent;
+
+/**
+ * Method {@link #collectData()} is called Synchronously with the Core.Cycle to
+ * collect values of Channels. Sending of values is then delegated to an
+ * asynchronous task.
+ *
+ *
+ * The logic tries to send changed values once per Cycle and all values once
+ * every {@link #SEND_VALUES_OF_ALL_CHANNELS_AFTER_SECONDS}.
+ */
+public class SendChannelValuesWorker {
+
+ private static final int SEND_VALUES_OF_ALL_CHANNELS_AFTER_SECONDS = 300; /* 5 minutes */
+
+ private final Logger log = LoggerFactory.getLogger(SendChannelValuesWorker.class);
+
+ private final BackendApiImpl parent;
+ private final ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.SECONDS,
+ new ArrayBlockingQueue<>(1), new ThreadPoolExecutor.DiscardOldestPolicy());
+
+ /**
+ * If true: next 'send' sends all channel values.
+ */
+ private AtomicBoolean sendValuesOfAllChannels = new AtomicBoolean(true);
+
+ /**
+ * Keeps the last timestamp when all channel values were sent.
+ */
+ private Instant lastSendValuesOfAllChannels = Instant.MIN;
+
+ /**
+ * Keeps the values of last successful send.
+ */
+ private Table lastAllValues = ImmutableTable.of();
+
+ protected SendChannelValuesWorker(BackendApiImpl parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * Called synchronously on AFTER_PROCESS_IMAGE event. Collects all the data and
+ * triggers asynchronous sending.
+ */
+ public synchronized void collectData() {
+ Instant now = Instant.now(this.parent.componentManager.getClock());
+
+ // Update the values of all channels
+ final List enabledComponents = this.parent.componentManager.getEnabledComponents();
+ final ImmutableTable allValues = this.collectData(enabledComponents);
+
+ // Add to send Queue
+ this.executor.execute(new SendTask(this, now, allValues));
+ }
+
+ /**
+ * Triggers sending all Channel values once.
+ */
+ public synchronized void sendValuesOfAllChannelsOnce() {
+ this.sendValuesOfAllChannels.set(true);
+ }
+
+ public void deactivate() {
+ // Shutdown executor
+ if (this.executor != null) {
+ try {
+ this.executor.shutdown();
+ this.executor.awaitTermination(5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ this.log.warn("tasks interrupted");
+ } finally {
+ if (!this.executor.isTerminated()) {
+ this.log.warn("cancel non-finished tasks");
+ }
+ this.executor.shutdownNow();
+ }
+ }
+ }
+
+ /**
+ * Cycles through all Channels and collects the value.
+ *
+ * @param enabledComponents the enabled components
+ * @return collected data
+ */
+ private ImmutableTable collectData(List enabledComponents) {
+ try {
+ return enabledComponents.parallelStream() //
+ .flatMap(component -> component.channels().parallelStream()) //
+ .filter(channel -> // Ignore WRITE_ONLY Channels
+ channel.channelDoc().getAccessMode() != AccessMode.WRITE_ONLY //
+ // Ignore Low-Priority Channels
+ && channel.channelDoc().getPersistencePriority()
+ .isAtLeast(this.parent.config.persistencePriority()))
+ .collect(ImmutableTable.toImmutableTable(c -> c.address().getComponentId(),
+ c -> c.address().getChannelId(), c -> c.value().asJson()));
+ } catch (Exception e) {
+ // ConcurrentModificationException can happen if Channels are dynamically added
+ // or removed
+ return ImmutableTable.of();
+ }
+ }
+
+ /*
+ * From here things run asynchronously.
+ */
+
+ private static class SendTask implements Runnable {
+
+ private final SendChannelValuesWorker parent;
+ private final Instant timestamp;
+ private final ImmutableTable allValues;
+
+ public SendTask(SendChannelValuesWorker parent, Instant timestamp,
+ ImmutableTable allValues) {
+ this.parent = parent;
+ this.timestamp = timestamp;
+ this.allValues = allValues;
+ }
+
+ @Override
+ public void run() {
+ // Holds the data of the last successful send. If the table is empty, it is also
+ // used as a marker to send all data.
+ final Table lastAllValues;
+
+ if (this.parent.sendValuesOfAllChannels.getAndSet(false)) {
+ // Send values of all Channels once in a while
+ lastAllValues = ImmutableTable.of();
+
+ } else if (Duration.between(this.parent.lastSendValuesOfAllChannels, this.timestamp)
+ .getSeconds() > SEND_VALUES_OF_ALL_CHANNELS_AFTER_SECONDS) {
+ // Send values of all Channels if explicitly asked for
+ lastAllValues = ImmutableTable.of();
+
+ } else {
+ // Actually use the kept 'lastSentValues'
+ lastAllValues = this.parent.lastAllValues;
+ }
+
+ // Round timestamp to Global Cycle-Time
+ final int cycleTime = this.parent.parent.cycle.getCycleTime();
+ final long timestampMillis = this.timestamp.toEpochMilli() / cycleTime * cycleTime;
+
+ // Prepare message values
+ Map sendValuesMap = new HashMap<>();
+
+ // Collect Changed values
+ for (Entry> row : allValues.rowMap().entrySet()) {
+ for (Entry column : row.getValue().entrySet()) {
+ if (!Objects.equals(column.getValue(), lastAllValues.get(row.getKey(), column.getKey()))) {
+ sendValuesMap.put(new ChannelAddress(row.getKey(), column.getKey()), column.getValue());
+ }
+ }
+ }
+
+ // Create JSON-RPC notification
+ TimestampedDataNotification message = new TimestampedDataNotification();
+ message.add(timestampMillis, sendValuesMap);
+
+ // Debug-Log
+ if (this.parent.parent.config.debugMode()) {
+ this.parent.parent.logInfo(this.parent.log,
+ "Sending [" + sendValuesMap.size() + " values]: " + sendValuesMap);
+ }
+
+ // Try to send
+ boolean wasSent = this.parent.parent.websocket.sendMessage(message);
+
+ // Set the UNABLE_TO_SEND channel
+ this.parent.parent.getUnableToSendChannel().setNextValue(!wasSent);
+
+ if (wasSent) {
+ // Successfully sent: update information for next runs
+ this.parent.lastAllValues = allValues;
+ if (lastAllValues.isEmpty()) {
+ // 'lastSentValues' was empty, i.e. all values were sent
+ this.parent.lastSendValuesOfAllChannels = this.timestamp;
+ }
+ }
+
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java
index c3668fb5c8d..400e659c52a 100644
--- a/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java
+++ b/io.openems.edge.controller.api.backend/src/io/openems/edge/controller/api/backend/WebsocketClient.java
@@ -74,4 +74,8 @@ protected void logInfo(Logger log, String message) {
protected void logWarn(Logger log, String message) {
this.parent.logWarn(log, message);
}
+
+ public boolean isConnected() {
+ return this.ws.isOpen();
+ }
}
diff --git a/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/BackendApiImplTest.java b/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/BackendApiImplTest.java
new file mode 100644
index 00000000000..4b0bae3ea9e
--- /dev/null
+++ b/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/BackendApiImplTest.java
@@ -0,0 +1,153 @@
+package io.openems.edge.controller.api.backend;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.net.Proxy.Type;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.temporal.ChronoUnit;
+import java.util.function.BiConsumer;
+
+import org.java_websocket.WebSocket;
+import org.junit.Test;
+
+import com.google.gson.JsonObject;
+
+import io.openems.common.OpenemsConstants;
+import io.openems.common.channel.PersistencePriority;
+import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
+import io.openems.common.exceptions.OpenemsException;
+import io.openems.common.jsonrpc.base.JsonrpcNotification;
+import io.openems.common.jsonrpc.notification.TimestampedDataNotification;
+import io.openems.common.types.ChannelAddress;
+import io.openems.common.utils.JsonUtils;
+import io.openems.common.websocket.DummyWebsocketServer;
+import io.openems.edge.common.sum.DummySum;
+import io.openems.edge.common.sum.Sum;
+import io.openems.edge.common.test.AbstractComponentTest.TestCase;
+import io.openems.edge.common.test.ComponentTest;
+import io.openems.edge.common.test.DummyComponentManager;
+import io.openems.edge.common.test.DummyCycle;
+import io.openems.edge.common.test.TimeLeapClock;
+
+public class BackendApiImplTest {
+
+ private static final String CTRL_ID = "ctrl0";
+
+ private static final String SUM_ID = OpenemsConstants.SUM_ID;
+ private static final ChannelAddress SUM_GRID_ACTIVE_POWER = new ChannelAddress(SUM_ID,
+ Sum.ChannelId.GRID_ACTIVE_POWER.id());
+ private static final ChannelAddress SUM_PRODUCTION_ACTIVE_POWER = new ChannelAddress(SUM_ID,
+ Sum.ChannelId.PRODUCTION_ACTIVE_POWER.id());
+
+ private static class TimestampedDataNotificationHandler implements io.openems.common.websocket.OnNotification {
+
+ protected boolean wasCalled = false;
+
+ private BiConsumer callback = (timestamp, values) -> {
+ };
+
+ public TimestampedDataNotificationHandler() {
+ }
+
+ public void onNotification(BiConsumer callback) {
+ this.wasCalled = false;
+ this.callback = callback;
+ }
+
+ public void waitForCallback(int timeout) throws InterruptedException, OpenemsException {
+ Instant start = Instant.now();
+ while (!this.wasCalled) {
+ if (Duration.between(start, Instant.now()).getSeconds() > timeout) {
+ throw new OpenemsException("Timeout [" + timeout + "s]");
+ }
+ Thread.sleep(100);
+ }
+ }
+
+ @Override
+ public void run(WebSocket websocket, JsonrpcNotification notification) throws OpenemsNamedException {
+ if (notification.getMethod().equals(TimestampedDataNotification.METHOD)) {
+ for (String timestamp : notification.getParams().keySet()) {
+ JsonObject values = JsonUtils.getAsJsonObject(notification.getParams().get(timestamp));
+ System.out.println(values);
+ this.callback.accept(Long.valueOf(timestamp), values);
+ this.wasCalled = true;
+ return;
+ }
+ }
+ }
+
+ }
+
+ @Test
+ public void test() throws Exception {
+ TimestampedDataNotificationHandler handler = new TimestampedDataNotificationHandler();
+
+ try (final DummyWebsocketServer server = DummyWebsocketServer.create() //
+ .onNotification(handler) //
+ .build()) {
+ int port = server.startBlocking();
+
+ final TimeLeapClock clock = new TimeLeapClock(
+ Instant.ofEpochSecond(1577836800L) /* starts at 1. January 2020 00:00:00 */, ZoneOffset.UTC);
+ final BackendApiImpl sut = new BackendApiImpl();
+ ComponentTest test = new ComponentTest(sut) //
+ .addReference("componentManager", new DummyComponentManager(clock)) //
+ .addReference("cycle", new DummyCycle(1000)) //
+ .addComponent(new DummySum()) //
+ .activate(MyConfig.create() //
+ .setId(CTRL_ID) //
+ .setUri("ws://localhost:" + port) //
+ .setApikey("12345") //
+ .setProxyType(Type.DIRECT) //
+ .setProxyAddress("") //
+ .setPersistencePriority(PersistencePriority.VERY_LOW) //
+ .build());
+
+ while (!sut.isConnected()) {
+ Thread.sleep(100);
+ }
+
+ // All Values initially
+ handler.onNotification((timestamp, values) -> {
+ assertTrue(values.size() > 50); // all values
+ });
+ test.next(new TestCase()); //
+ handler.waitForCallback(5000);
+
+ // Only changed value
+ handler.onNotification((timestamp, values) -> {
+ assertTrue(values.size() == 1); // exactly one value
+ assertEquals(Integer.valueOf(1000),
+ JsonUtils.getAsOptionalInt(values, SUM_GRID_ACTIVE_POWER.toString()).get());
+ });
+ test.next(new TestCase() //
+ .input(SUM_GRID_ACTIVE_POWER, 1000) //
+ );
+ handler.waitForCallback(5000);
+
+ // Only changed value
+ handler.onNotification((timestamp, values) -> {
+ assertTrue(values.size() == 1); // exactly one value
+ assertEquals(Integer.valueOf(2000),
+ JsonUtils.getAsOptionalInt(values, SUM_PRODUCTION_ACTIVE_POWER.toString()).get());
+ });
+ test.next(new TestCase() //
+ .input(SUM_PRODUCTION_ACTIVE_POWER, 2000) //
+ );
+ handler.waitForCallback(5000);
+
+ // All values after 5 minutes
+ handler.onNotification((timestamp, values) -> {
+ assertTrue(values.size() > 50); // all values
+ });
+ test.next(new TestCase() //
+ .timeleap(clock, 6, ChronoUnit.MINUTES));
+ handler.waitForCallback(5000);
+ }
+ }
+
+}
diff --git a/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/MyConfig.java b/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/MyConfig.java
new file mode 100644
index 00000000000..46771968219
--- /dev/null
+++ b/io.openems.edge.controller.api.backend/test/io/openems/edge/controller/api/backend/MyConfig.java
@@ -0,0 +1,131 @@
+package io.openems.edge.controller.api.backend;
+
+import java.net.Proxy.Type;
+
+import io.openems.common.channel.PersistencePriority;
+import io.openems.edge.common.test.AbstractComponentConfig;
+
+@SuppressWarnings("all")
+public class MyConfig extends AbstractComponentConfig implements Config {
+
+ protected static class Builder {
+ private String id;
+ public String apikey;
+ public String uri;
+ public String proxyAddress;
+ public int proxyPort;
+ public Type proxyType;
+ public int apiTimeout;
+ public PersistencePriority persistencePriority;
+ public boolean debugMode;
+
+ private Builder() {
+ }
+
+ public Builder setId(String id) {
+ this.id = id;
+ return this;
+ }
+
+ public Builder setApikey(String apikey) {
+ this.apikey = apikey;
+ return this;
+ }
+
+ public Builder setUri(String uri) {
+ this.uri = uri;
+ return this;
+ }
+
+ public Builder setProxyAddress(String proxyAddress) {
+ this.proxyAddress = proxyAddress;
+ return this;
+ }
+
+ public Builder setProxyPort(int proxyPort) {
+ this.proxyPort = proxyPort;
+ return this;
+ }
+
+ public Builder setProxyType(Type proxyType) {
+ this.proxyType = proxyType;
+ return this;
+ }
+
+ public Builder setApiTimeout(int apiTimeout) {
+ this.apiTimeout = apiTimeout;
+ return this;
+ }
+
+ public Builder setPersistencePriority(PersistencePriority persistencePriority) {
+ this.persistencePriority = persistencePriority;
+ return this;
+ }
+
+ public Builder setDebugMode(boolean debugMode) {
+ this.debugMode = debugMode;
+ return this;
+ }
+
+ public MyConfig build() {
+ return new MyConfig(this);
+ }
+ }
+
+ /**
+ * Create a Config builder.
+ *
+ * @return a {@link Builder}
+ */
+ public static Builder create() {
+ return new Builder();
+ }
+
+ private final Builder builder;
+
+ private MyConfig(Builder builder) {
+ super(Config.class, builder.id);
+ this.builder = builder;
+ }
+
+ @Override
+ public String apikey() {
+ return this.builder.apikey;
+ }
+
+ @Override
+ public String uri() {
+ return this.builder.uri;
+ }
+
+ @Override
+ public String proxyAddress() {
+ return this.builder.proxyAddress;
+ }
+
+ @Override
+ public int proxyPort() {
+ return this.builder.proxyPort;
+ }
+
+ @Override
+ public Type proxyType() {
+ return this.builder.proxyType;
+ }
+
+ @Override
+ public int apiTimeout() {
+ return this.builder.apiTimeout;
+ }
+
+ @Override
+ public PersistencePriority persistencePriority() {
+ return this.builder.persistencePriority;
+ }
+
+ @Override
+ public boolean debugMode() {
+ return this.builder.debugMode;
+ }
+
+}
\ No newline at end of file
diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolExportXlsxRequest.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolExportXlsxRequest.java
index 0d702b0be8f..a99c5a1b1f9 100644
--- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolExportXlsxRequest.java
+++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolExportXlsxRequest.java
@@ -1,7 +1,5 @@
package io.openems.edge.controller.api.modbus.jsonrpc;
-import java.util.UUID;
-
import com.google.gson.JsonObject;
import io.openems.common.jsonrpc.base.JsonrpcRequest;
@@ -23,11 +21,11 @@ public class GetModbusProtocolExportXlsxRequest extends JsonrpcRequest {
public static final String METHOD = "getModbusProtocolExportXlsx";
public GetModbusProtocolExportXlsxRequest() {
- this(UUID.randomUUID());
+ super(METHOD);
}
- public GetModbusProtocolExportXlsxRequest(UUID id) {
- super(id, METHOD);
+ private GetModbusProtocolExportXlsxRequest(JsonrpcRequest request) {
+ super(request, METHOD);
}
@Override
diff --git a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolRequest.java b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolRequest.java
index ed07c9415c2..4a4bbfa9adc 100644
--- a/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolRequest.java
+++ b/io.openems.edge.controller.api.modbus/src/io/openems/edge/controller/api/modbus/jsonrpc/GetModbusProtocolRequest.java
@@ -1,7 +1,5 @@
package io.openems.edge.controller.api.modbus.jsonrpc;
-import java.util.UUID;
-
import com.google.gson.JsonObject;
import io.openems.common.jsonrpc.base.JsonrpcRequest;
@@ -24,11 +22,11 @@ public class GetModbusProtocolRequest extends JsonrpcRequest {
public static final String METHOD = "getModbusProtocol";
public GetModbusProtocolRequest() {
- this(UUID.randomUUID());
+ super(METHOD);
}
- public GetModbusProtocolRequest(UUID id) {
- super(id, METHOD);
+ private GetModbusProtocolRequest(JsonrpcRequest request) {
+ super(request, METHOD);
}
@Override
diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnOpen.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnOpen.java
index f00cb4ba612..fcc9b771457 100644
--- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnOpen.java
+++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnOpen.java
@@ -47,7 +47,7 @@ public void run(WebSocket ws, JsonObject handshake) {
// send authentication notification
AuthenticateWithSessionIdNotification notification = new AuthenticateWithSessionIdNotification(
- token, Utils.getEdgeMetadata(user.getRole()));
+ token.toString(), Utils.getEdgeMetadata(user.getRole()));
this.parent.server.sendMessage(ws, notification);
// log
diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnRequest.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnRequest.java
index 7c534e5e3b4..026c3960df3 100644
--- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnRequest.java
+++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/OnRequest.java
@@ -183,7 +183,7 @@ private CompletableFuture handleAuthenticateWithPassword
this.parent.sessionTokens.put(wsData.getSessionToken(), user);
// TODO unset on logout!
return CompletableFuture.completedFuture(new AuthenticateWithPasswordResponse(request.getId(),
- wsData.getSessionToken(), Utils.getEdgeMetadata(user.getRole())));
+ wsData.getSessionToken().toString(), Utils.getEdgeMetadata(user.getRole())));
}
/**
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 f102730482d..458c2c18629 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,6 +60,8 @@ public class WebsocketApi extends AbstractOpenemsComponent
public static final int DEFAULT_PORT = 8075;
+ private final static int POOL_SIZE = 10;
+
protected final ApiWorker apiWorker = new ApiWorker(this);
private final SystemLogHandler systemLogHandler;
@@ -111,7 +113,7 @@ protected void activate(ComponentContext context, Config config) {
return;
}
this.apiWorker.setTimeoutSeconds(config.apiTimeout());
- this.startServer(config.port());
+ this.startServer(config.port(), POOL_SIZE, false);
}
@Deactivate
@@ -123,10 +125,12 @@ protected void deactivate() {
/**
* Create and start new server.
*
- * @param port the port
+ * @param port the port
+ * @param poolSize number of threads dedicated to handle the tasks
+ * @param debugMode activate a regular debug log about the state of the tasks
*/
- private synchronized void startServer(int port) {
- this.server = new WebsocketServer(this, "Websocket Api", port);
+ private synchronized void startServer(int port, int poolSize, boolean debugMode) {
+ this.server = new WebsocketServer(this, "Websocket Api", port, poolSize, debugMode);
this.server.start();
}
diff --git a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketServer.java b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketServer.java
index b341142fc84..db347bd090b 100644
--- a/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketServer.java
+++ b/io.openems.edge.controller.api.websocket/src/io/openems/edge/controller/api/websocket/WebsocketServer.java
@@ -13,8 +13,8 @@ public class WebsocketServer extends AbstractWebsocketServer {
private final OnError onError;
private final OnClose onClose;
- public WebsocketServer(WebsocketApi parent, String name, int port) {
- super(name, port);
+ public WebsocketServer(WebsocketApi parent, String name, int port, int poolSize, boolean debugMode) {
+ super(name, port, poolSize, debugMode);
this.parent = parent;
this.onOpen = new OnOpen(parent);
this.onRequest = new OnRequest(parent);
diff --git a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/Controller.java b/io.openems.edge.controller.api/src/io/openems/edge/controller/api/Controller.java
index cab60de764a..34e22a63c67 100644
--- a/io.openems.edge.controller.api/src/io/openems/edge/controller/api/Controller.java
+++ b/io.openems.edge.controller.api/src/io/openems/edge/controller/api/Controller.java
@@ -4,6 +4,7 @@
import io.openems.common.channel.AccessMode;
import io.openems.common.channel.Level;
+import io.openems.common.channel.PersistencePriority;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.edge.common.channel.Doc;
import io.openems.edge.common.channel.StateChannel;
@@ -24,6 +25,7 @@ public interface Controller extends OpenemsComponent {
public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
RUN_FAILED(Doc.of(Level.FAULT) //
+ .persistencePriority(PersistencePriority.HIGH) //
.text("Running the Controller failed"));
private final Doc doc;
diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java
index b6d91486094..444ca211b65 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/ComponentManagerImpl.java
@@ -31,6 +31,9 @@
import org.osgi.service.metatype.MetaTypeService;
import org.slf4j.Logger;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonNull;
+
import io.openems.common.OpenemsConstants;
import io.openems.common.exceptions.OpenemsError;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
@@ -312,11 +315,18 @@ protected CompletableFuture handleUpdateComponentConfigR
for (Property property : request.getProperties()) {
// do not allow certain properties to be updated, like pid and service.pid
if (!EdgeConfig.ignorePropertyKey(property.getName())) {
- Object value = JsonUtils.getAsBestType(property.getValue());
- if (value instanceof Object[] && ((Object[]) value).length == 0) {
- value = new String[0];
+ JsonElement jValue = property.getValue();
+ if (jValue == null || jValue == JsonNull.INSTANCE) {
+ // Remove NULL property
+ properties.remove(property.getName());
+ } else {
+ // Add updated Property
+ Object value = JsonUtils.getAsBestType(property.getValue());
+ if (value instanceof Object[] && ((Object[]) value).length == 0) {
+ value = new String[0];
+ }
+ properties.put(property.getName(), value);
}
- properties.put(property.getName(), value);
}
}
diff --git a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/OsgiValidateWorker.java b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/OsgiValidateWorker.java
index 1d5b341b577..63c1417943a 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/componentmanager/OsgiValidateWorker.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/componentmanager/OsgiValidateWorker.java
@@ -174,7 +174,17 @@ private static void updateInactiveComponentsUsingScr(Map defecti
private static void updateInactiveComponentsUsingConfigurationAdmin(Map defectiveComponents,
List enabledComponents, Configuration[] configs) {
for (Configuration config : configs) {
- Dictionary properties = config.getProperties();
+ Dictionary properties;
+ try {
+ properties = config.getProperties();
+ if (properties == null) {
+ // configuration was just created and update has not been called
+ continue;
+ }
+ } catch (IllegalStateException e) {
+ // Configuration has been deleted
+ continue;
+ }
String componentId = (String) properties.get("id");
if (componentId != null) {
if (defectiveComponents.containsKey(componentId)) {
diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/ExecuteSystemCommandRequest.java b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/ExecuteSystemCommandRequest.java
index e9b4634900b..6e36e0ee621 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/ExecuteSystemCommandRequest.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/ExecuteSystemCommandRequest.java
@@ -91,7 +91,8 @@ public ExecuteSystemCommandRequest(String command, boolean runInBackground, int
public ExecuteSystemCommandRequest(UUID id, String command, boolean runInBackground, int timeoutSeconds,
Optional username, Optional password) {
- super(id, METHOD);
+ super(id, METHOD,
+ timeoutSeconds + JsonrpcRequest.DEFAULT_TIMEOUT_SECONDS /* reuse timeoutSeconds with some buffer */);
this.command = command;
this.runInBackground = runInBackground;
this.timeoutSeconds = timeoutSeconds;
diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetNetworkConfigRequest.java b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetNetworkConfigRequest.java
index bb4726f916e..b302d8937c1 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetNetworkConfigRequest.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/GetNetworkConfigRequest.java
@@ -1,7 +1,5 @@
package io.openems.edge.core.host.jsonrpc;
-import java.util.UUID;
-
import com.google.gson.JsonObject;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
@@ -32,15 +30,15 @@ public class GetNetworkConfigRequest extends JsonrpcRequest {
* @throws OpenemsNamedException on error
*/
public static GetNetworkConfigRequest from(JsonrpcRequest r) throws OpenemsException {
- return new GetNetworkConfigRequest(r.getId());
+ return new GetNetworkConfigRequest(r);
}
public GetNetworkConfigRequest() {
- this(UUID.randomUUID());
+ super(METHOD);
}
- public GetNetworkConfigRequest(UUID id) {
- super(id, METHOD);
+ private GetNetworkConfigRequest(JsonrpcRequest request) {
+ super(request, METHOD);
}
@Override
diff --git a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/SetNetworkConfigRequest.java b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/SetNetworkConfigRequest.java
index cce6946bbfd..00fd4f774b1 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/SetNetworkConfigRequest.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/host/jsonrpc/SetNetworkConfigRequest.java
@@ -3,7 +3,6 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
-import java.util.UUID;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
@@ -52,18 +51,19 @@ public static SetNetworkConfigRequest from(JsonrpcRequest r) throws OpenemsNamed
for (Entry entry : jInterfaces.entrySet()) {
interfaces.add(NetworkInterface.from(entry.getKey(), JsonUtils.getAsJsonObject(entry.getValue())));
}
- return new SetNetworkConfigRequest(r.getId(), interfaces);
+ return new SetNetworkConfigRequest(r, interfaces);
}
private final List> networkInterfaces;
public SetNetworkConfigRequest(List> interfaces) {
- this(UUID.randomUUID(), interfaces);
+ super(METHOD);
+ this.networkInterfaces = interfaces;
}
- public SetNetworkConfigRequest(UUID id, List> networkInterfaces) {
- super(id, METHOD);
- this.networkInterfaces = networkInterfaces;
+ private SetNetworkConfigRequest(JsonrpcRequest request, List> interfaces) {
+ super(request, METHOD);
+ this.networkInterfaces = interfaces;
}
@Override
diff --git a/io.openems.edge.core/src/io/openems/edge/core/predictormanager/Get24HoursPredictionRequest.java b/io.openems.edge.core/src/io/openems/edge/core/predictormanager/Get24HoursPredictionRequest.java
index eb34b821b1e..2d09cdb307c 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/predictormanager/Get24HoursPredictionRequest.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/predictormanager/Get24HoursPredictionRequest.java
@@ -2,7 +2,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.UUID;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
@@ -31,6 +30,14 @@ public class Get24HoursPredictionRequest extends JsonrpcRequest {
public static final String METHOD = "get24HoursPrediction";
+ /**
+ * Create {@link Get24HoursPredictionRequest} from a template
+ * {@link JsonrpcRequest}.
+ *
+ * @param r the template {@link JsonrpcRequest}
+ * @return the {@link Get24HoursPredictionRequest}
+ * @throws OpenemsNamedException on parse error
+ */
public static Get24HoursPredictionRequest from(JsonrpcRequest r) throws OpenemsNamedException {
JsonObject p = r.getParams();
JsonArray cs = JsonUtils.getAsJsonArray(p, "channels");
@@ -38,17 +45,18 @@ public static Get24HoursPredictionRequest from(JsonrpcRequest r) throws OpenemsN
for (JsonElement c : cs) {
channels.add(ChannelAddress.fromString(JsonUtils.getAsString(c)));
}
- return new Get24HoursPredictionRequest(r.getId(), channels);
+ return new Get24HoursPredictionRequest(r, channels);
}
private final List channels;
public Get24HoursPredictionRequest(List channels) {
- this(UUID.randomUUID(), channels);
+ super(METHOD);
+ this.channels = channels;
}
- public Get24HoursPredictionRequest(UUID id, List channels) {
- super(id, METHOD);
+ private Get24HoursPredictionRequest(JsonrpcRequest request, List channels) {
+ super(request, METHOD);
this.channels = channels;
}
@@ -63,6 +71,11 @@ public JsonObject getParams() {
.build();
}
+ /**
+ * Gets the {@link ChannelAddress}es.
+ *
+ * @return a list of {@link ChannelAddress}
+ */
public List getChannels() {
return this.channels;
}
diff --git a/io.openems.edge.core/src/io/openems/edge/core/predictormanager/Get24HoursPredictionResponse.java b/io.openems.edge.core/src/io/openems/edge/core/predictormanager/Get24HoursPredictionResponse.java
index cf13edaaf9a..674038be72d 100644
--- a/io.openems.edge.core/src/io/openems/edge/core/predictormanager/Get24HoursPredictionResponse.java
+++ b/io.openems.edge.core/src/io/openems/edge/core/predictormanager/Get24HoursPredictionResponse.java
@@ -50,8 +50,13 @@ public JsonObject getResult() {
return j;
}
+ /**
+ * Gets the {@link Prediction24Hours}s per {@link ChannelAddress}.
+ *
+ * @return a map of Predictions
+ */
public Map getPredictions() {
- return predictions;
+ return this.predictions;
}
}
diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/AsymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/AsymmetricEss.java
index ec9bac688e8..155e7511960 100644
--- a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/AsymmetricEss.java
+++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/AsymmetricEss.java
@@ -5,6 +5,7 @@
import org.osgi.annotation.versioning.ProviderType;
import io.openems.common.channel.AccessMode;
+import io.openems.common.channel.PersistencePriority;
import io.openems.common.channel.Unit;
import io.openems.common.types.OpenemsType;
import io.openems.edge.common.channel.Doc;
@@ -30,6 +31,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
ACTIVE_POWER_L1(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.HIGH) //
.text(POWER_DOC_TEXT) //
),
/**
@@ -44,6 +46,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
ACTIVE_POWER_L2(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.HIGH) //
.text(POWER_DOC_TEXT) //
),
/**
@@ -58,6 +61,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
ACTIVE_POWER_L3(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.HIGH) //
.text(POWER_DOC_TEXT) //
),
/**
@@ -72,6 +76,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
REACTIVE_POWER_L1(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.VOLT_AMPERE_REACTIVE) //
+ .persistencePriority(PersistencePriority.HIGH) //
.text(POWER_DOC_TEXT) //
),
/**
@@ -86,6 +91,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
REACTIVE_POWER_L2(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.VOLT_AMPERE_REACTIVE) //
+ .persistencePriority(PersistencePriority.HIGH) //
.text(POWER_DOC_TEXT) //
),
/**
@@ -100,6 +106,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
REACTIVE_POWER_L3(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.VOLT_AMPERE_REACTIVE) //
+ .persistencePriority(PersistencePriority.HIGH) //
.text(POWER_DOC_TEXT) //
);
@@ -151,7 +158,7 @@ public default Value getActivePowerL1() {
public default void _setActivePowerL1(Integer value) {
this.getActivePowerL1Channel().setNextValue(value);
}
-
+
/**
* Internal method to set the 'nextValue' on {@link ChannelId#ACTIVE_POWER_L1}
* Channel.
@@ -190,7 +197,7 @@ public default Value getActivePowerL2() {
public default void _setActivePowerL2(Integer value) {
this.getActivePowerL2Channel().setNextValue(value);
}
-
+
/**
* Internal method to set the 'nextValue' on {@link ChannelId#ACTIVE_POWER_L2}
* Channel.
@@ -229,7 +236,7 @@ public default Value getActivePowerL3() {
public default void _setActivePowerL3(Integer value) {
this.getActivePowerL3Channel().setNextValue(value);
}
-
+
/**
* Internal method to set the 'nextValue' on {@link ChannelId#ACTIVE_POWER_L3}
* Channel.
@@ -268,7 +275,7 @@ public default Value getReactivePowerL1() {
public default void _setReactivePowerL1(Integer value) {
this.getReactivePowerL1Channel().setNextValue(value);
}
-
+
/**
* Internal method to set the 'nextValue' on {@link ChannelId#REACTIVE_POWER_L1}
* Channel.
@@ -307,7 +314,7 @@ public default Value getReactivePowerL2() {
public default void _setReactivePowerL2(Integer value) {
this.getReactivePowerL2Channel().setNextValue(value);
}
-
+
/**
* Internal method to set the 'nextValue' on {@link ChannelId#REACTIVE_POWER_L2}
* Channel.
@@ -346,7 +353,7 @@ public default Value getReactivePowerL3() {
public default void _setReactivePowerL3(Integer value) {
this.getReactivePowerL3Channel().setNextValue(value);
}
-
+
/**
* Internal method to set the 'nextValue' on {@link ChannelId#REACTIVE_POWER_L3}
* Channel.
diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/HybridEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/HybridEss.java
index 641af12230e..681068beb1a 100644
--- a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/HybridEss.java
+++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/HybridEss.java
@@ -2,6 +2,7 @@
import org.osgi.annotation.versioning.ProviderType;
+import io.openems.common.channel.PersistencePriority;
import io.openems.common.channel.Unit;
import io.openems.common.types.OpenemsType;
import io.openems.edge.common.channel.Doc;
@@ -34,6 +35,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
DC_DISCHARGE_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.HIGH) //
.text(POWER_DOC_TEXT) //
),
/**
@@ -46,7 +48,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
DC_CHARGE_ENERGY(Doc.of(OpenemsType.LONG) //
- .unit(Unit.WATT_HOURS)),
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* DC Discharge Energy.
*
@@ -57,7 +60,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
DC_DISCHARGE_ENERGY(Doc.of(OpenemsType.LONG) //
- .unit(Unit.WATT_HOURS)),;
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.HIGH)); //
private final Doc doc;
diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedAsymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedAsymmetricEss.java
index 217a68528d8..971cc7655eb 100644
--- a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedAsymmetricEss.java
+++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/ManagedAsymmetricEss.java
@@ -3,6 +3,7 @@
import org.osgi.annotation.versioning.ProviderType;
import io.openems.common.channel.AccessMode;
+import io.openems.common.channel.PersistencePriority;
import io.openems.common.channel.Unit;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.common.types.OpenemsType;
@@ -299,7 +300,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
DEBUG_SET_ACTIVE_POWER_L1(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)), //
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Holds settings of Reactive Power for debugging
*
@@ -314,7 +316,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
DEBUG_SET_REACTIVE_POWER_L1(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.VOLT_AMPERE_REACTIVE)), //
+ .unit(Unit.VOLT_AMPERE_REACTIVE) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Holds settings of Active Power L2 for debugging
*
@@ -329,7 +332,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
DEBUG_SET_ACTIVE_POWER_L2(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)), //
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Holds settings of Reactive Power for debugging
*
@@ -344,7 +348,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
DEBUG_SET_REACTIVE_POWER_L2(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.VOLT_AMPERE_REACTIVE)), //
+ .unit(Unit.VOLT_AMPERE_REACTIVE) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Holds settings of Active Power L1 for debugging
*
@@ -359,7 +364,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
DEBUG_SET_ACTIVE_POWER_L3(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)), //
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Holds settings of Reactive Power for debugging
*
@@ -374,8 +380,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
DEBUG_SET_REACTIVE_POWER_L3(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.VOLT_AMPERE_REACTIVE)), //
- ;
+ .unit(Unit.VOLT_AMPERE_REACTIVE) //
+ .persistencePriority(PersistencePriority.HIGH)); //
private final Doc doc;
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 535e54ccabf..2967d1071dd 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
@@ -4,6 +4,7 @@
import io.openems.common.channel.AccessMode;
import io.openems.common.channel.Level;
+import io.openems.common.channel.PersistencePriority;
import io.openems.common.channel.Unit;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.common.exceptions.OpenemsException;
@@ -40,7 +41,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
ALLOWED_CHARGE_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)), //
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Holds the currently maximum allowed discharge power. This value is commonly
* defined by current battery limitations.
@@ -53,7 +55,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
ALLOWED_DISCHARGE_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)), //
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Sets a fixed Active Power.
*
@@ -193,7 +196,8 @@ public void accept(Channel channel) {
*
*/
DEBUG_SET_ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT)), //
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Holds settings of Reactive Power for debugging.
*
@@ -207,7 +211,8 @@ public void accept(Channel channel) {
*
*/
DEBUG_SET_REACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.VOLT_AMPERE_REACTIVE)), //
+ .unit(Unit.VOLT_AMPERE_REACTIVE) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* StateChannel is set when calling applyPower() failed.
*
@@ -220,6 +225,7 @@ public void accept(Channel channel) {
*
*/
APPLY_POWER_FAILED(Doc.of(Level.FAULT) //
+ .persistencePriority(PersistencePriority.HIGH) //
.text("Applying the Active/Reactive Power failed"));
private final Doc doc;
diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java
index c43f541c938..0793c9841cf 100644
--- a/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java
+++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/api/SymmetricEss.java
@@ -3,6 +3,7 @@
import org.osgi.annotation.versioning.ProviderType;
import io.openems.common.channel.AccessMode;
+import io.openems.common.channel.PersistencePriority;
import io.openems.common.channel.Unit;
import io.openems.common.types.OpenemsType;
import io.openems.edge.common.channel.Channel;
@@ -32,7 +33,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
SOC(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.PERCENT)),
+ .unit(Unit.PERCENT) //
+ .persistencePriority(PersistencePriority.HIGH)),
/**
* Capacity.
*
@@ -45,7 +47,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
* @since 2019.5.0
*/
CAPACITY(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.WATT_HOURS)),
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.HIGH)),
/**
* Grid-Mode.
*
@@ -55,7 +58,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
* Range: 0=Undefined, 1=On-Grid, 2=Off-Grid
*
*/
- GRID_MODE(Doc.of(GridMode.values())),
+ GRID_MODE(Doc.of(GridMode.values()) //
+ .persistencePriority(PersistencePriority.HIGH)),
/**
* Active Power.
*
@@ -68,6 +72,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
ACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.HIGH) //
.text(POWER_DOC_TEXT) //
),
/**
@@ -82,6 +87,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
REACTIVE_POWER(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.VOLT_AMPERE_REACTIVE) //
+ .persistencePriority(PersistencePriority.HIGH) //
.text(POWER_DOC_TEXT) //
),
/**
@@ -96,7 +102,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
MAX_APPARENT_POWER(Doc.of(OpenemsType.INTEGER) //
- .unit(Unit.VOLT_AMPERE)), //
+ .unit(Unit.VOLT_AMPERE) //
+ .persistencePriority(PersistencePriority.HIGH)),
/**
* Active Charge Energy.
*
@@ -107,7 +114,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
ACTIVE_CHARGE_ENERGY(Doc.of(OpenemsType.LONG) //
- .unit(Unit.WATT_HOURS)),
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.HIGH)),
/**
* Active Discharge Energy.
*
@@ -118,7 +126,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
ACTIVE_DISCHARGE_ENERGY(Doc.of(OpenemsType.LONG) //
- .unit(Unit.WATT_HOURS)),
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.HIGH)),
/**
* Min Cell Voltage.
*
@@ -133,7 +142,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
MIN_CELL_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.MILLIVOLT) //
- ),
+ .persistencePriority(PersistencePriority.HIGH)),
/**
* Max Cell Voltage.
*
@@ -148,7 +157,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
MAX_CELL_VOLTAGE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.MILLIVOLT) //
- ),
+ .persistencePriority(PersistencePriority.HIGH)),
/**
* Min Cell Temperature.
*
@@ -163,7 +172,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
MIN_CELL_TEMPERATURE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.DEGREE_CELSIUS) //
- ),
+ .persistencePriority(PersistencePriority.HIGH)),
/**
* Max Cell Temperature.
*
@@ -178,7 +187,7 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*/
MAX_CELL_TEMPERATURE(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.DEGREE_CELSIUS) //
- );
+ .persistencePriority(PersistencePriority.HIGH));
private final Doc doc;
diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/dccharger/api/EssDcCharger.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/dccharger/api/EssDcCharger.java
index 0cd967dfd01..ebd069b2af0 100644
--- a/io.openems.edge.ess.api/src/io/openems/edge/ess/dccharger/api/EssDcCharger.java
+++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/dccharger/api/EssDcCharger.java
@@ -2,6 +2,7 @@
import org.osgi.annotation.versioning.ProviderType;
+import io.openems.common.channel.PersistencePriority;
import io.openems.common.channel.Unit;
import io.openems.common.types.OpenemsType;
import io.openems.common.utils.IntUtils;
@@ -28,7 +29,9 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
* Implementation Note: value is automatically derived from ACTUAL_POWER
*
*/
- MAX_ACTUAL_POWER(Doc.of(OpenemsType.INTEGER).unit(Unit.WATT)), //
+ MAX_ACTUAL_POWER(Doc.of(OpenemsType.INTEGER)//
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.HIGH)), //
/**
* Actual Power
*
@@ -39,24 +42,28 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
* Range: positive
*
*/
- ACTUAL_POWER(Doc.of(OpenemsType.INTEGER).unit(Unit.WATT).onInit(channel -> {
- channel.onSetNextValue(value -> {
- /*
- * Fill Max Actual Power channel
- */
- if (value.asOptional().isPresent()) {
- int newValue = (int) (Integer) value.get();
- Channel maxActualPowerChannel = channel.getComponent().channel(ChannelId.MAX_ACTUAL_POWER);
- int maxActualPower = maxActualPowerChannel.value().orElse(0);
- int maxNextActualPower = maxActualPowerChannel.getNextValue().orElse(0);
- if (newValue > Math.max(maxActualPower, maxNextActualPower)) {
- // avoid getting called too often -> round to 100
- newValue = IntUtils.roundToPrecision(newValue, Round.AWAY_FROM_ZERO, 100);
- maxActualPowerChannel.setNextValue(newValue);
- }
- }
- });
- })),
+ ACTUAL_POWER(Doc.of(OpenemsType.INTEGER) //
+ .unit(Unit.WATT) //
+ .persistencePriority(PersistencePriority.HIGH) //
+ .onInit(channel -> {
+ channel.onSetNextValue(value -> {
+ /*
+ * Fill Max Actual Power channel
+ */
+ if (value.asOptional().isPresent()) {
+ int newValue = (int) (Integer) value.get();
+ Channel maxActualPowerChannel = channel.getComponent()
+ .channel(ChannelId.MAX_ACTUAL_POWER);
+ int maxActualPower = maxActualPowerChannel.value().orElse(0);
+ int maxNextActualPower = maxActualPowerChannel.getNextValue().orElse(0);
+ if (newValue > Math.max(maxActualPower, maxNextActualPower)) {
+ // avoid getting called too often -> round to 100
+ newValue = IntUtils.roundToPrecision(newValue, Round.AWAY_FROM_ZERO, 100);
+ maxActualPowerChannel.setNextValue(newValue);
+ }
+ }
+ });
+ })),
/**
* Actual Energy
*
@@ -67,7 +74,8 @@ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
*
*/
ACTUAL_ENERGY(Doc.of(OpenemsType.LONG) //
- .unit(Unit.WATT_HOURS));
+ .unit(Unit.WATT_HOURS) //
+ .persistencePriority(PersistencePriority.HIGH)); //
private final Doc doc;
diff --git a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/SolverStrategy.java b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/SolverStrategy.java
index 0aea023b6f1..b651a05567a 100644
--- a/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/SolverStrategy.java
+++ b/io.openems.edge.ess.api/src/io/openems/edge/ess/power/api/SolverStrategy.java
@@ -21,12 +21,12 @@ private SolverStrategy(int value, String name) {
@Override
public int getValue() {
- return value;
+ return this.value;
}
@Override
public String getName() {
- return name;
+ return this.name;
}
@Override
diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractGenericEssChannelManager.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractGenericEssChannelManager.java
new file mode 100644
index 00000000000..68c9210389e
--- /dev/null
+++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractGenericEssChannelManager.java
@@ -0,0 +1,96 @@
+package io.openems.edge.ess.generic.common;
+
+import io.openems.edge.battery.api.Battery;
+import io.openems.edge.batteryinverter.api.ManagedSymmetricBatteryInverter;
+import io.openems.edge.batteryinverter.api.SymmetricBatteryInverter;
+import io.openems.edge.common.channel.AbstractChannelListenerManager;
+import io.openems.edge.common.channel.Channel;
+import io.openems.edge.common.channel.ChannelId;
+import io.openems.edge.common.component.ClockProvider;
+import io.openems.edge.common.component.OpenemsComponent;
+import io.openems.edge.ess.api.SymmetricEss;
+
+/**
+ * Helper wrapping class to handle everything related to Channels; in particular
+ * calculating the Ess-Channels based on the Channels of the Battery and
+ * Battery-Inverter. Takes care of registering and unregistering listeners.
+ */
+public class AbstractGenericEssChannelManager
+ extends AbstractChannelListenerManager {
+
+ private final GenericManagedEss parent;
+ private final AllowedChargeDischargeHandler allowedChargeDischargeHandler;
+
+ public AbstractGenericEssChannelManager(GenericManagedEss parent) {
+ this.parent = parent;
+ this.allowedChargeDischargeHandler = new AllowedChargeDischargeHandler(parent);
+ }
+
+ /**
+ * Called on Component activate().
+ *
+ * @param clockProvider the {@link ClockProvider}
+ * @param battery the {@link Battery}
+ * @param batteryInverter the {@link ManagedSymmetricBatteryInverter}
+ */
+ public void activate(ClockProvider clockProvider, Battery battery,
+ ManagedSymmetricBatteryInverter batteryInverter) {
+ /*
+ * Battery
+ */
+ this.addOnSetNextValueListener(battery, Battery.ChannelId.DISCHARGE_MIN_VOLTAGE,
+ (ignored) -> this.allowedChargeDischargeHandler.accept(clockProvider, battery));
+ this.addOnSetNextValueListener(battery, Battery.ChannelId.DISCHARGE_MAX_CURRENT,
+ (ignored) -> this.allowedChargeDischargeHandler.accept(clockProvider, battery));
+ this.addOnSetNextValueListener(battery, Battery.ChannelId.CHARGE_MAX_VOLTAGE,
+ (ignored) -> this.allowedChargeDischargeHandler.accept(clockProvider, battery));
+ this.addOnSetNextValueListener(battery, Battery.ChannelId.CHARGE_MAX_CURRENT,
+ (ignored) -> this.allowedChargeDischargeHandler.accept(clockProvider, battery));
+ this.addCopyListener(battery, //
+ Battery.ChannelId.CAPACITY, //
+ SymmetricEss.ChannelId.CAPACITY);
+ this.addCopyListener(battery, //
+ Battery.ChannelId.SOC, //
+ SymmetricEss.ChannelId.SOC);
+
+ /*
+ * Battery-Inverter
+ */
+ this.addCopyListener(batteryInverter, //
+ SymmetricBatteryInverter.ChannelId.ACTIVE_CHARGE_ENERGY, //
+ SymmetricEss.ChannelId.ACTIVE_CHARGE_ENERGY);
+ this.addCopyListener(batteryInverter, //
+ SymmetricBatteryInverter.ChannelId.ACTIVE_DISCHARGE_ENERGY, //
+ SymmetricEss.ChannelId.ACTIVE_DISCHARGE_ENERGY);
+ this.addCopyListener(batteryInverter, //
+ SymmetricBatteryInverter.ChannelId.ACTIVE_POWER, //
+ SymmetricEss.ChannelId.ACTIVE_POWER);
+ this.addCopyListener(batteryInverter, //
+ SymmetricBatteryInverter.ChannelId.GRID_MODE, //
+ SymmetricEss.ChannelId.GRID_MODE);
+ this.addCopyListener(batteryInverter, //
+ SymmetricBatteryInverter.ChannelId.MAX_APPARENT_POWER, //
+ SymmetricEss.ChannelId.MAX_APPARENT_POWER);
+ this.addCopyListener(batteryInverter, //
+ SymmetricBatteryInverter.ChannelId.REACTIVE_POWER, //
+ SymmetricEss.ChannelId.REACTIVE_POWER);
+ }
+
+ /**
+ * Adds a Copy-Listener. It listens on setNextValue() and copies the value to
+ * the target channel.
+ *
+ * @param the Channel-Type
+ * @param sourceComponent the source component - Battery or BatteryInverter
+ * @param sourceChannelId the source ChannelId
+ * @param targetChannelId the target ChannelId
+ */
+ private void addCopyListener(OpenemsComponent sourceComponent, ChannelId sourceChannelId,
+ ChannelId targetChannelId) {
+ this.addOnSetNextValueListener(sourceComponent, sourceChannelId, (value) -> {
+ Channel targetChannel = this.parent.channel(targetChannelId);
+ targetChannel.setNextValue(value);
+ });
+ }
+
+}
diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractGenericManagedEss.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractGenericManagedEss.java
new file mode 100644
index 00000000000..095126d4580
--- /dev/null
+++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AbstractGenericManagedEss.java
@@ -0,0 +1,237 @@
+package io.openems.edge.ess.generic.common;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.openems.common.channel.AccessMode;
+import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
+import io.openems.edge.battery.api.Battery;
+import io.openems.edge.batteryinverter.api.BatteryInverterConstraint;
+import io.openems.edge.batteryinverter.api.ManagedSymmetricBatteryInverter;
+import io.openems.edge.batteryinverter.api.SymmetricBatteryInverter;
+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.common.event.EdgeEventConstants;
+import io.openems.edge.common.modbusslave.ModbusSlave;
+import io.openems.edge.common.modbusslave.ModbusSlaveTable;
+import io.openems.edge.common.startstop.StartStop;
+import io.openems.edge.common.startstop.StartStopConfig;
+import io.openems.edge.common.startstop.StartStoppable;
+import io.openems.edge.ess.api.ManagedSymmetricEss;
+import io.openems.edge.ess.api.SymmetricEss;
+import io.openems.edge.ess.generic.common.statemachine.Context;
+import io.openems.edge.ess.generic.common.statemachine.StateMachine;
+import io.openems.edge.ess.generic.common.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.Pwr;
+import io.openems.edge.ess.power.api.Relationship;
+
+/**
+ * Parent class for different implementations of Managed Energy Storage Systems,
+ * consisting of a Battery-Inverter component and a Battery component.
+ */
+public abstract class AbstractGenericManagedEss
+ extends AbstractOpenemsComponent implements GenericManagedEss, ManagedSymmetricEss, SymmetricEss,
+ OpenemsComponent, EventHandler, StartStoppable, ModbusSlave {
+
+ private final Logger log = LoggerFactory.getLogger(AbstractGenericManagedEss.class);
+
+ /**
+ * Manages the {@link State}s of the StateMachine.
+ */
+ private final StateMachine stateMachine = new StateMachine(State.UNDEFINED);
+
+ /**
+ * Helper wrapping class to handle everything related to Channels.
+ *
+ * @return the {@link AbstractGenericEssChannelManager}
+ */
+ protected abstract AbstractGenericEssChannelManager getChannelManager();
+
+ protected abstract ComponentManager getComponentManager();
+
+ protected abstract BATTERY getBattery();
+
+ protected abstract BATTERY_INVERTER getBatteryInverter();
+
+ private StartStopConfig startStopConfig = StartStopConfig.AUTO;
+
+ protected AbstractGenericManagedEss(io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds,
+ io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) {
+ super(firstInitialChannelIds, furtherInitialChannelIds);
+ }
+
+ @Override
+ protected void activate(ComponentContext context, String id, String alias, boolean enabled) {
+ throw new IllegalArgumentException("Use the other activate() method!");
+ }
+
+ protected void activate(ComponentContext context, String id, String alias, boolean enabled,
+ StartStopConfig startStopConfig, ConfigurationAdmin cm, String batteryInverterId, String batteryId) {
+ super.activate(context, id, alias, enabled);
+ this.startStopConfig = startStopConfig;
+
+ // update filter for 'BatteryInverter'
+ if (OpenemsComponent.updateReferenceFilter(cm, this.servicePid(), "batteryInverter", batteryInverterId)) {
+ return;
+ }
+
+ // update filter for 'Battery'
+ if (OpenemsComponent.updateReferenceFilter(cm, this.servicePid(), "battery", batteryId)) {
+ return;
+ }
+
+ this.getChannelManager().activate(this.getComponentManager(), this.getBattery(), this.getBatteryInverter());
+ }
+
+ protected void deactivate() {
+ this.getChannelManager().deactivate();
+ super.deactivate();
+ }
+
+ @Override
+ public void handleEvent(Event event) {
+ if (!this.isEnabled()) {
+ return;
+ }
+ switch (event.getTopic()) {
+
+ case EdgeEventConstants.TOPIC_CYCLE_AFTER_PROCESS_IMAGE:
+ this.handleStateMachine();
+ break;
+ }
+ }
+
+ /**
+ * Handles the State-Machine.
+ */
+ private void handleStateMachine() {
+ // Store the current State
+ this.channel(GenericManagedEss.ChannelId.STATE_MACHINE).setNextValue(this.stateMachine.getCurrentState());
+
+ // Initialize 'Start-Stop' Channel
+ this._setStartStop(StartStop.UNDEFINED);
+
+ // Prepare Context
+ Context context = new Context(this, this.getBattery(), this.getBatteryInverter());
+
+ // Call the StateMachine
+ try {
+ this.stateMachine.run(context);
+
+ this.channel(GenericManagedEss.ChannelId.RUN_FAILED).setNextValue(false);
+
+ } catch (OpenemsNamedException e) {
+ this.channel(GenericManagedEss.ChannelId.RUN_FAILED).setNextValue(true);
+ this.logError(this.log, "StateMachine failed: " + e.getMessage());
+ }
+ }
+
+ @Override
+ public String debugLog() {
+ return "SoC:" + this.getSoc().asString() //
+ + "|L:" + this.getActivePower().asString() //
+ + "|Allowed:" //
+ + this.getAllowedChargePower().asStringWithoutUnit() + ";" //
+ + this.getAllowedDischargePower().asString() //
+ + "|" + this.channel(GenericManagedEss.ChannelId.STATE_MACHINE).value().asOptionString();
+ }
+
+ /**
+ * Forwards the power request to the {@link SymmetricBatteryInverter}.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void applyPower(int activePower, int reactivePower) throws OpenemsNamedException {
+ this.getBatteryInverter().run(this.getBattery(), activePower, reactivePower);
+ }
+
+ /**
+ * Retrieves PowerPrecision from {@link SymmetricBatteryInverter}.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public int getPowerPrecision() {
+ return this.getBatteryInverter().getPowerPrecision();
+ }
+
+ /**
+ * Retrieves StaticConstraints from {@link SymmetricBatteryInverter}.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public Constraint[] getStaticConstraints() throws OpenemsNamedException {
+
+ List result = new ArrayList();
+
+ // Get BatteryInverterConstraints
+ BatteryInverterConstraint[] constraints = this.getBatteryInverter().getStaticConstraints();
+
+ for (int i = 0; i < constraints.length; i++) {
+ BatteryInverterConstraint c = constraints[i];
+ result.add(this.getPower().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()]);
+ }
+
+ private AtomicReference startStopTarget = new AtomicReference(StartStop.UNDEFINED);
+
+ @Override
+ public void setStartStop(StartStop value) {
+ if (this.startStopTarget.getAndSet(value) != value) {
+ // Set only if value changed
+ this.stateMachine.forceNextState(State.UNDEFINED);
+ }
+ }
+
+ @Override
+ public StartStop getStartStopTarget() {
+ switch (this.startStopConfig) {
+ case AUTO:
+ // read StartStop-Channel
+ return this.startStopTarget.get();
+
+ case START:
+ // force START
+ return StartStop.START;
+
+ case STOP:
+ // force STOP
+ return StartStop.STOP;
+ }
+
+ assert false;
+ return StartStop.UNDEFINED; // can never happen
+ }
+
+ @Override
+ public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) {
+ return new ModbusSlaveTable(//
+ OpenemsComponent.getModbusSlaveNatureTable(accessMode), //
+ SymmetricEss.getModbusSlaveNatureTable(accessMode), //
+ ManagedSymmetricEss.getModbusSlaveNatureTable(accessMode) //
+ );
+ }
+}
diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/AllowedChargeDischargeHandler.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AllowedChargeDischargeHandler.java
similarity index 94%
rename from io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/AllowedChargeDischargeHandler.java
rename to io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AllowedChargeDischargeHandler.java
index 0b121b7b5ca..7bc859f05ac 100644
--- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/AllowedChargeDischargeHandler.java
+++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/AllowedChargeDischargeHandler.java
@@ -1,4 +1,4 @@
-package io.openems.edge.ess.generic.symmetric;
+package io.openems.edge.ess.generic.common;
import java.time.Duration;
import java.time.Instant;
@@ -9,6 +9,7 @@
import io.openems.edge.common.component.ClockProvider;
import io.openems.edge.common.startstop.StartStoppable;
import io.openems.edge.ess.api.ManagedSymmetricEss;
+import io.openems.edge.ess.generic.symmetric.ChannelManager;
/**
* Helper class to handle calculation of Allowed-Charge-Power and
@@ -17,7 +18,7 @@
*/
public class AllowedChargeDischargeHandler implements BiConsumer {
- public final static float DISCHARGE_EFFICIENCY_FACTOR = 0.95F;
+ public static final float DISCHARGE_EFFICIENCY_FACTOR = 0.95F;
/**
* Allow a maximum increase per second.
@@ -25,7 +26,7 @@ public class AllowedChargeDischargeHandler implements BiConsumer
* 5 % of possible allowed charge/discharge power
*/
- public final static float MAX_INCREASE_PERCENTAGE = 0.05F;
+ public static final float MAX_INCREASE_PERCENTAGE = 0.05F;
private final ManagedSymmetricEss parent;
@@ -63,6 +64,7 @@ public void accept(ClockProvider clockProvider, Battery battery) {
* parameters. Result is stored in 'allowedChargePower' and
* 'allowedDischargePower' variables - both as positive values!
*
+ * @param clockProvider the {@link ClockProvider}
* @param isStarted is the ESS started?
* @param chargeMaxCurrent the {@link Battery.ChannelId#CHARGE_MAX_CURRENT}
* @param dischargeMaxCurrent the {@link Battery.ChannelId#DISHARGE_MAX_CURRENT}
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/common/GenericManagedEss.java
similarity index 93%
rename from io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/GenericManagedSymmetricEss.java
rename to io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/GenericManagedEss.java
index 3835f47c977..18f60f41b6a 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/common/GenericManagedEss.java
@@ -1,4 +1,4 @@
-package io.openems.edge.ess.generic.symmetric;
+package io.openems.edge.ess.generic.common;
import io.openems.common.channel.AccessMode;
import io.openems.common.channel.Level;
@@ -14,9 +14,9 @@
import io.openems.edge.common.startstop.StartStoppable;
import io.openems.edge.ess.api.ManagedSymmetricEss;
import io.openems.edge.ess.api.SymmetricEss;
-import io.openems.edge.ess.generic.symmetric.statemachine.StateMachine.State;
+import io.openems.edge.ess.generic.common.statemachine.StateMachine.State;
-public interface GenericManagedSymmetricEss extends ManagedSymmetricEss, StartStoppable, ModbusSlave {
+public interface GenericManagedEss extends ManagedSymmetricEss, StartStoppable, ModbusSlave {
/**
* Efficiency factor to calculate AC Charge/Discharge limits from DC. Used at
@@ -68,8 +68,8 @@ public default ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) {
SymmetricEss.getModbusSlaveNatureTable(accessMode), //
ManagedSymmetricEss.getModbusSlaveNatureTable(accessMode), //
StartStoppable.getModbusSlaveNatureTable(accessMode), //
- ModbusSlaveNatureTable.of(GenericManagedSymmetricEss.class, accessMode, 100) //
- .channel(0, GenericManagedSymmetricEss.ChannelId.STATE_MACHINE, ModbusType.UINT16) //
+ ModbusSlaveNatureTable.of(GenericManagedEss.class, accessMode, 100) //
+ .channel(0, GenericManagedEss.ChannelId.STATE_MACHINE, ModbusType.UINT16) //
.build());
}
diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/package-info.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/package-info.java
similarity index 77%
rename from io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/package-info.java
rename to io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/package-info.java
index ab8586d01ed..1fd7a5acc1b 100644
--- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/package-info.java
+++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/package-info.java
@@ -1,4 +1,4 @@
@org.osgi.annotation.versioning.Version("1.0.0")
@org.osgi.annotation.bundle.Export
// TODO remove, once Ess-Sinexcel is migrated to Battery-Inverter; see #1389
-package io.openems.edge.ess.generic.symmetric;
+package io.openems.edge.ess.generic.common;
diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/statemachine/Context.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/statemachine/Context.java
new file mode 100644
index 00000000000..a41bb06644e
--- /dev/null
+++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/statemachine/Context.java
@@ -0,0 +1,18 @@
+package io.openems.edge.ess.generic.common.statemachine;
+
+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.common.GenericManagedEss;
+
+public class Context extends AbstractContext {
+
+ protected final Battery battery;
+ protected final ManagedSymmetricBatteryInverter batteryInverter;
+
+ public Context(GenericManagedEss parent, Battery battery, ManagedSymmetricBatteryInverter batteryInverter) {
+ super(parent);
+ this.battery = battery;
+ this.batteryInverter = batteryInverter;
+ }
+}
\ No newline at end of file
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/common/statemachine/ErrorHandler.java
similarity index 80%
rename from io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/ErrorHandler.java
rename to io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/statemachine/ErrorHandler.java
index 3cdba1a9e36..fec12f30de1 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/common/statemachine/ErrorHandler.java
@@ -1,4 +1,4 @@
-package io.openems.edge.ess.generic.symmetric.statemachine;
+package io.openems.edge.ess.generic.common.statemachine;
import java.time.Duration;
import java.time.Instant;
@@ -6,8 +6,8 @@
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;
+import io.openems.edge.ess.generic.common.GenericManagedEss;
+import io.openems.edge.ess.generic.common.statemachine.StateMachine.State;
public class ErrorHandler extends StateHandler {
@@ -24,7 +24,7 @@ protected void onEntry(Context context) throws OpenemsNamedException {
@Override
protected void onExit(Context context) throws OpenemsNamedException {
- GenericManagedSymmetricEss ess = context.getParent();
+ GenericManagedEss ess = context.getParent();
ess._setMaxBatteryStartAttemptsFault(false);
ess._setMaxBatteryStopAttemptsFault(false);
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/common/statemachine/StartBatteryHandler.java
similarity index 73%
rename from io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryHandler.java
rename to io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/statemachine/StartBatteryHandler.java
index e693b9670de..6f2579f6490 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/common/statemachine/StartBatteryHandler.java
@@ -1,12 +1,12 @@
-package io.openems.edge.ess.generic.symmetric.statemachine;
+package io.openems.edge.ess.generic.common.statemachine;
import java.time.Duration;
import java.time.Instant;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
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;
+import io.openems.edge.ess.generic.common.GenericManagedEss;
+import io.openems.edge.ess.generic.common.statemachine.StateMachine.State;
public class StartBatteryHandler extends StateHandler {
@@ -17,13 +17,13 @@ public class StartBatteryHandler extends StateHandler {
protected void onEntry(Context context) throws OpenemsNamedException {
this.lastAttempt = Instant.MIN;
this.attemptCounter = 0;
- GenericManagedSymmetricEss ess = context.getParent();
+ GenericManagedEss ess = context.getParent();
ess._setMaxBatteryStartAttemptsFault(false);
}
@Override
public State runAndGetNextState(Context context) throws OpenemsNamedException {
- GenericManagedSymmetricEss ess = context.getParent();
+ GenericManagedEss ess = context.getParent();
if (context.battery.isStarted()) {
// TODO should we check here the other parameters defined in Battery Nature.
@@ -31,11 +31,11 @@ public State runAndGetNextState(Context context) throws OpenemsNamedException {
}
boolean isMaxStartTimePassed = Duration.between(this.lastAttempt, Instant.now())
- .getSeconds() > GenericManagedSymmetricEss.RETRY_COMMAND_SECONDS;
+ .getSeconds() > GenericManagedEss.RETRY_COMMAND_SECONDS;
if (isMaxStartTimePassed) {
// First try - or waited long enough for next try
- if (this.attemptCounter > GenericManagedSymmetricEss.RETRY_COMMAND_MAX_ATTEMPTS) {
+ if (this.attemptCounter > GenericManagedEss.RETRY_COMMAND_MAX_ATTEMPTS) {
// Too many tries
ess._setMaxBatteryStartAttemptsFault(true);
return State.UNDEFINED;
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/common/statemachine/StartBatteryInverterHandler.java
similarity index 72%
rename from io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartBatteryInverterHandler.java
rename to io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/statemachine/StartBatteryInverterHandler.java
index b8b1ea2beeb..9887a0e3b5b 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/common/statemachine/StartBatteryInverterHandler.java
@@ -1,12 +1,12 @@
-package io.openems.edge.ess.generic.symmetric.statemachine;
+package io.openems.edge.ess.generic.common.statemachine;
import java.time.Duration;
import java.time.Instant;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
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;
+import io.openems.edge.ess.generic.common.GenericManagedEss;
+import io.openems.edge.ess.generic.common.statemachine.StateMachine.State;
public class StartBatteryInverterHandler extends StateHandler {
@@ -17,24 +17,24 @@ public class StartBatteryInverterHandler extends StateHandler {
protected void onEntry(Context context) throws OpenemsNamedException {
this.lastAttempt = Instant.MIN;
this.attemptCounter = 0;
- GenericManagedSymmetricEss ess = context.getParent();
+ GenericManagedEss ess = context.getParent();
ess._setMaxBatteryInverterStartAttemptsFault(false);
}
@Override
public State runAndGetNextState(Context context) throws OpenemsNamedException {
- GenericManagedSymmetricEss ess = context.getParent();
+ GenericManagedEss ess = context.getParent();
if (context.batteryInverter.isStarted()) {
return State.STARTED;
}
boolean isMaxStartTimePassed = Duration.between(this.lastAttempt, Instant.now())
- .getSeconds() > GenericManagedSymmetricEss.RETRY_COMMAND_SECONDS;
+ .getSeconds() > GenericManagedEss.RETRY_COMMAND_SECONDS;
if (isMaxStartTimePassed) {
// First try - or waited long enough for next try
- if (this.attemptCounter > GenericManagedSymmetricEss.RETRY_COMMAND_MAX_ATTEMPTS) {
+ if (this.attemptCounter > GenericManagedEss.RETRY_COMMAND_MAX_ATTEMPTS) {
// Too many tries
ess._setMaxBatteryInverterStartAttemptsFault(true);
return State.UNDEFINED;
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/common/statemachine/StartedHandler.java
similarity index 66%
rename from io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StartedHandler.java
rename to io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/statemachine/StartedHandler.java
index 9c25fa222cb..3d50b8f7468 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/common/statemachine/StartedHandler.java
@@ -1,15 +1,15 @@
-package io.openems.edge.ess.generic.symmetric.statemachine;
+package io.openems.edge.ess.generic.common.statemachine;
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;
+import io.openems.edge.ess.generic.common.GenericManagedEss;
+import io.openems.edge.ess.generic.common.statemachine.StateMachine.State;
public class StartedHandler extends StateHandler {
@Override
public State runAndGetNextState(Context context) {
- GenericManagedSymmetricEss ess = context.getParent();
+ GenericManagedEss ess = context.getParent();
if (ess.hasFaults()) {
return State.UNDEFINED;
diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StateMachine.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/statemachine/StateMachine.java
similarity index 96%
rename from io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StateMachine.java
rename to io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/statemachine/StateMachine.java
index 166e52771cf..70da6405b36 100644
--- a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StateMachine.java
+++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/statemachine/StateMachine.java
@@ -1,4 +1,4 @@
-package io.openems.edge.ess.generic.symmetric.statemachine;
+package io.openems.edge.ess.generic.common.statemachine;
import com.google.common.base.CaseFormat;
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/common/statemachine/StopBatteryHandler.java
similarity index 71%
rename from io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryHandler.java
rename to io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/statemachine/StopBatteryHandler.java
index b1333dfd8f3..e6f2af40d67 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/common/statemachine/StopBatteryHandler.java
@@ -1,12 +1,12 @@
-package io.openems.edge.ess.generic.symmetric.statemachine;
+package io.openems.edge.ess.generic.common.statemachine;
import java.time.Duration;
import java.time.Instant;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
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;
+import io.openems.edge.ess.generic.common.GenericManagedEss;
+import io.openems.edge.ess.generic.common.statemachine.StateMachine.State;
public class StopBatteryHandler extends StateHandler {
@@ -17,24 +17,24 @@ public class StopBatteryHandler extends StateHandler {
protected void onEntry(Context context) throws OpenemsNamedException {
this.lastAttempt = Instant.MIN;
this.attemptCounter = 0;
- GenericManagedSymmetricEss ess = context.getParent();
+ GenericManagedEss ess = context.getParent();
ess._setMaxBatteryStopAttemptsFault(false);
}
@Override
public State runAndGetNextState(Context context) throws OpenemsNamedException {
- GenericManagedSymmetricEss ess = context.getParent();
+ GenericManagedEss ess = context.getParent();
if (context.battery.isStopped()) {
return State.STOPPED;
}
boolean isMaxStartTimePassed = Duration.between(this.lastAttempt, Instant.now())
- .getSeconds() > GenericManagedSymmetricEss.RETRY_COMMAND_SECONDS;
+ .getSeconds() > GenericManagedEss.RETRY_COMMAND_SECONDS;
if (isMaxStartTimePassed) {
// First try - or waited long enough for next try
- if (this.attemptCounter > GenericManagedSymmetricEss.RETRY_COMMAND_MAX_ATTEMPTS) {
+ if (this.attemptCounter > GenericManagedEss.RETRY_COMMAND_MAX_ATTEMPTS) {
// Too many tries
ess._setMaxBatteryStopAttemptsFault(true);
return State.UNDEFINED;
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/common/statemachine/StopBatteryInverterHandler.java
similarity index 72%
rename from io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StopBatteryInverterHandler.java
rename to io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/statemachine/StopBatteryInverterHandler.java
index ea8f392a0ff..3aebdb36bac 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/common/statemachine/StopBatteryInverterHandler.java
@@ -1,12 +1,12 @@
-package io.openems.edge.ess.generic.symmetric.statemachine;
+package io.openems.edge.ess.generic.common.statemachine;
import java.time.Duration;
import java.time.Instant;
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
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;
+import io.openems.edge.ess.generic.common.GenericManagedEss;
+import io.openems.edge.ess.generic.common.statemachine.StateMachine.State;
public class StopBatteryInverterHandler extends StateHandler {
@@ -17,24 +17,24 @@ public class StopBatteryInverterHandler extends StateHandler {
protected void onEntry(Context context) throws OpenemsNamedException {
this.lastAttempt = Instant.MIN;
this.attemptCounter = 0;
- GenericManagedSymmetricEss ess = context.getParent();
+ GenericManagedEss ess = context.getParent();
ess._setMaxBatteryInverterStopAttemptsFault(false);
}
@Override
public State runAndGetNextState(Context context) throws OpenemsNamedException {
- GenericManagedSymmetricEss ess = context.getParent();
+ GenericManagedEss ess = context.getParent();
if (context.batteryInverter.isStopped()) {
return State.STOP_BATTERY;
}
boolean isMaxStartTimePassed = Duration.between(this.lastAttempt, Instant.now())
- .getSeconds() > GenericManagedSymmetricEss.RETRY_COMMAND_SECONDS;
+ .getSeconds() > GenericManagedEss.RETRY_COMMAND_SECONDS;
if (isMaxStartTimePassed) {
// First try - or waited long enough for next try
- if (this.attemptCounter > GenericManagedSymmetricEss.RETRY_COMMAND_MAX_ATTEMPTS) {
+ if (this.attemptCounter > GenericManagedEss.RETRY_COMMAND_MAX_ATTEMPTS) {
// Too many tries
ess._setMaxBatteryInverterStopAttemptsFault(true);
return State.UNDEFINED;
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/common/statemachine/StoppedHandler.java
similarity index 66%
rename from io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/StoppedHandler.java
rename to io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/statemachine/StoppedHandler.java
index 41d3178477a..3c107166071 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/common/statemachine/StoppedHandler.java
@@ -1,15 +1,15 @@
-package io.openems.edge.ess.generic.symmetric.statemachine;
+package io.openems.edge.ess.generic.common.statemachine;
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;
+import io.openems.edge.ess.generic.common.GenericManagedEss;
+import io.openems.edge.ess.generic.common.statemachine.StateMachine.State;
public class StoppedHandler extends StateHandler {
@Override
public State runAndGetNextState(Context context) {
- GenericManagedSymmetricEss ess = context.getParent();
+ GenericManagedEss ess = context.getParent();
if (ess.hasFaults()) {
return State.UNDEFINED;
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/common/statemachine/UndefinedHandler.java
similarity index 75%
rename from io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/symmetric/statemachine/UndefinedHandler.java
rename to io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/common/statemachine/UndefinedHandler.java
index 6ed6f647c71..42c54a09980 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/common/statemachine/UndefinedHandler.java
@@ -1,14 +1,14 @@
-package io.openems.edge.ess.generic.symmetric.statemachine;
+package io.openems.edge.ess.generic.common.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;
+import io.openems.edge.ess.generic.common.GenericManagedEss;
+import io.openems.edge.ess.generic.common.statemachine.StateMachine.State;
public class UndefinedHandler extends StateHandler {
@Override
public State runAndGetNextState(Context context) {
- GenericManagedSymmetricEss ess = context.getParent();
+ GenericManagedEss ess = context.getParent();
switch (ess.getStartStopTarget()) {
case UNDEFINED:
// Stuck in UNDEFINED State
diff --git a/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/hybrid/ChannelManager.java b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/hybrid/ChannelManager.java
new file mode 100644
index 00000000000..cf42e11c884
--- /dev/null
+++ b/io.openems.edge.ess.generic/src/io/openems/edge/ess/generic/hybrid/ChannelManager.java
@@ -0,0 +1,14 @@
+package io.openems.edge.ess.generic.hybrid;
+
+import io.openems.edge.battery.api.Battery;
+import io.openems.edge.batteryinverter.api.HybridManagedSymmetricBatteryInverter;
+import io.openems.edge.ess.generic.common.AbstractGenericEssChannelManager;
+import io.openems.edge.ess.generic.common.GenericManagedEss;
+
+public class ChannelManager extends AbstractGenericEssChannelManager