Skip to content

Commit

Permalink
FEMS Backports 2025-02-07 (#3005)
Browse files Browse the repository at this point in the history
**This fixes a critical bug in Time-of-Use-Tariff Optimizer in https://github.com/OpenEMS/openems/releases/tag/2025.2.0**

* Edge
  * AppCenter: Fix selecting relays
    - added filter for initial check if an app can be installed based on available relays (CheckRelayCountFilters.deviceHardware)
    - properly handle selecting multiple relays (array value)
    - moved required setting to right places
    - added missing options hint in SelectGroupBuilder if none are available
    - only apply modal of safe input when confirmed
  * ToU Optimizer: fix BALANCING fallback schedule
    - A endless loop causes fallback schedule. Bug became visible after recently added null-check
    - Copied logic from new Optimizer.java: src/branch/develop/io.openems.edge.energy/src/io/openems/edge/energy/optimizer/Optimizer.java#L198-L202
  * EVCS: new PhaseRotation which supports better Modbus handling
    - Native EVCS support for PhaseRotation
    - switched nature enum `PhaseRotation` to a new format
    - added method `Evcs.getPhaseRotation()` (BREAKING CHANGE)
    - applied code cleanup
  * JsonSerializer: improved serialization
    - added tests
    - added StringParser of e. g. UUID, SemanticVersion, ChannelAddress, ....
    - added number parsing
    - added polymorphic parsing for subclasses of one type
    - added boolean parsing
    - EmptyObject to reduce duplicated empty request/response
    - added nullable paths for every type
    - added primitive path with strict parsing
    - updated a lot of json rpc methods

* UI
  * History consumption chart non deprecated evcs not taken into account for total consumption
    - in history chart "consumption". Ensure that non deprecatedEvcs (new implementations) are not added to "sonstiger Verbrauch"
    - if deprecatedEvcs is not implemented (chargepower channel nature) then it is added to consumption metered
  • Loading branch information
sfeilmeier authored Feb 7, 2025
1 parent a85f5d6 commit cd0ffd1
Show file tree
Hide file tree
Showing 187 changed files with 11,683 additions and 991 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.google.gson.JsonObject;

import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.common.jsonrpc.serialization.EndpointRequestType;
import io.openems.common.utils.JsonUtils;

/**
Expand All @@ -26,6 +27,23 @@
*/
public class GenericJsonrpcRequest extends JsonrpcRequest {

/**
* Creates a GenericJsonrpcRequest from the provided object.
*
* @param <REQUEST> the original type of the request
* @param endpointType the definition of the endpoint
* @param request the request to transform into a
* {@link GenericJsonrpcRequest}
* @return the created {@link GenericJsonrpcRequest}
*/
public static <REQUEST> GenericJsonrpcRequest createRequest(//
EndpointRequestType<REQUEST, ?> endpointType, //
REQUEST request //
) {
return new GenericJsonrpcRequest(endpointType.getMethod(),
endpointType.getRequestSerializer().serialize(request).getAsJsonObject());
}

/**
* Parses the String to a {@link GenericJsonrpcRequest}.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package io.openems.common.jsonrpc.request;

import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer;
import static io.openems.common.utils.JsonUtils.toJsonArray;
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.mapping;
import static java.util.stream.Collectors.toList;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -15,6 +19,8 @@
import io.openems.common.exceptions.OpenemsException;
import io.openems.common.function.ThrowingFunction;
import io.openems.common.jsonrpc.base.JsonrpcRequest;
import io.openems.common.jsonrpc.serialization.JsonElementPath;
import io.openems.common.jsonrpc.serialization.JsonSerializer;
import io.openems.common.utils.JsonUtils;

/**
Expand Down Expand Up @@ -50,12 +56,58 @@ public static class PaginationOptions {
private final SearchParams searchParams;
private final String query;

/**
* Returns a {@link JsonSerializer} for a
* {@link GetEdgesRequest.PaginationOptions.SearchParams}.
*
* @return the created {@link JsonSerializer}
*/
public static JsonSerializer<GetEdgesRequest.PaginationOptions> serializer() {
return jsonObjectSerializer(GetEdgesRequest.PaginationOptions.class, //
json -> new GetEdgesRequest.PaginationOptions(//
json.getInt("page"), //
json.getOptionalInt("limit").orElse(DEFAULT_LIMIT), //
json.getString("query"), //
json.getObject("searchParams", SearchParams.serializer())), //
obj -> JsonUtils.buildJsonObject() //
.addProperty("page", obj.page) //
.addProperty("limit", obj.limit) //
.addProperty("query", obj.query) //
.add("searchParams", SearchParams.serializer().serialize(obj.searchParams)) //
.build());
}

public record SearchParams(//
List<String> productTypes, //
List<Level> sumStates, //
boolean searchIsOnline, //
boolean isOnline //
) {
/**
* Returns a {@link JsonSerializer} for a
* {@link GetEdgesRequest.PaginationOptions.SearchParams}.
*
* @return the created {@link JsonSerializer}
*/
public static JsonSerializer<GetEdgesRequest.PaginationOptions.SearchParams> serializer() {
return jsonObjectSerializer(GetEdgesRequest.PaginationOptions.SearchParams.class, json -> {
final var isOnline = json.getBooleanPathNullable("isOnline");
return new GetEdgesRequest.PaginationOptions.SearchParams(//
json.getList("producttype", JsonElementPath::getAsString), //
json.getJsonArrayPath("sumState").collect(mapping(t -> t.getAsEnum(Level.class), toList())), //
isOnline.isPresent(), //
isOnline.getOrDefault(false));
}, obj -> JsonUtils.buildJsonObject() //
.add("producttype", obj.productTypes().stream() //
.map(JsonPrimitive::new) //
.collect(toJsonArray()))
.add("sumState", obj.sumStates().stream() //
.map(Level::name) //
.map(JsonPrimitive::new) //
.collect(toJsonArray()))
.onlyIf(obj.searchIsOnline(), t -> t.addProperty("isOnline", obj.isOnline())) //
.build());
}

/**
* Creates a {@link SearchParams} from a {@link JsonObject}.
Expand Down Expand Up @@ -119,7 +171,7 @@ public static PaginationOptions from(JsonObject params) throws OpenemsNamedExcep
return new PaginationOptions(page, limit, query, searchParams);
}

private PaginationOptions(int page, int limit, String query, SearchParams searchParams) {
public PaginationOptions(int page, int limit, String query, SearchParams searchParams) {
this.page = page;
this.limit = limit;
this.query = query;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Optional;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeSet;

Expand Down Expand Up @@ -96,29 +97,31 @@ public static QueryHistoricTimeseriesDataRequest from(JsonrpcRequest r) throws O

private final ZonedDateTime fromDate;
private final ZonedDateTime toDate;
private final TreeSet<ChannelAddress> channels = new TreeSet<>();
private final Set<ChannelAddress> channels;

/**
* Resolution of the data or empty for automatic.
*/
private final Optional<Resolution> resolution;

private QueryHistoricTimeseriesDataRequest(JsonrpcRequest request, ZonedDateTime fromDate, ZonedDateTime toDate,
Optional<Resolution> resolution) throws OpenemsNamedException {
Optional<Resolution> resolution) {
super(request, QueryHistoricTimeseriesDataRequest.METHOD);

this.fromDate = fromDate;
this.toDate = toDate;
this.resolution = resolution;
this.channels = new TreeSet<>();
}

public QueryHistoricTimeseriesDataRequest(ZonedDateTime fromDate, ZonedDateTime toDate,
Optional<Resolution> resolution) throws OpenemsNamedException {
Optional<Resolution> resolution, Set<ChannelAddress> channels) {
super(QueryHistoricTimeseriesDataRequest.METHOD);

this.fromDate = fromDate;
this.toDate = toDate;
this.resolution = resolution;
this.channels = channels;
}

private void addChannel(ChannelAddress address) {
Expand Down Expand Up @@ -170,7 +173,7 @@ public ZonedDateTime getToDate() {
*
* @return Set of {@link ChannelAddress}
*/
public TreeSet<ChannelAddress> getChannels() {
public Set<ChannelAddress> getChannels() {
return this.channels;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,16 @@ private QueryHistoricTimeseriesExportXlxsRequest(JsonrpcRequest request, ZonedDa
this.toDate = toDate;
}

public QueryHistoricTimeseriesExportXlxsRequest(ZonedDateTime fromDate, ZonedDateTime toDate)
throws OpenemsNamedException {
super(QueryHistoricTimeseriesExportXlxsRequest.METHOD);

DateUtils.assertSameTimezone(fromDate, toDate);
this.timezoneDiff = ZoneOffset.from(fromDate).getTotalSeconds();
this.fromDate = fromDate;
this.toDate = toDate;
}

@Override
public JsonObject getParams() {
return JsonUtils.buildJsonObject() //
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.openems.common.jsonrpc.request;

import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer;

import java.util.ArrayList;
import java.util.List;

Expand All @@ -10,6 +12,7 @@

import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.common.jsonrpc.base.JsonrpcRequest;
import io.openems.common.jsonrpc.serialization.JsonSerializer;
import io.openems.common.utils.JsonUtils;

/**
Expand Down Expand Up @@ -106,6 +109,23 @@ protected static List<Property> from(JsonArray j) throws OpenemsNamedException {
return properties;
}

/**
* Returns a {@link JsonSerializer} for a
* {@link UpdateComponentConfigRequest.Property}.
*
* @return the created {@link JsonSerializer}
*/
public static JsonSerializer<UpdateComponentConfigRequest.Property> serializer() {
return jsonObjectSerializer(UpdateComponentConfigRequest.Property.class, //
json -> new UpdateComponentConfigRequest.Property(//
json.getString("name"), //
json.getJsonElement("value")), //
obj -> JsonUtils.buildJsonObject() //
.addProperty("name", obj.name) //
.add("value", obj.value) //
.build());
}

private final String name;
private final JsonElement value;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.openems.common.jsonrpc.response;

import static io.openems.common.jsonrpc.serialization.JsonSerializerUtil.jsonObjectSerializer;

import java.time.ZonedDateTime;
import java.util.List;
import java.util.UUID;
Expand All @@ -10,6 +12,7 @@
import io.openems.common.channel.Level;
import io.openems.common.jsonrpc.base.JsonrpcResponseSuccess;
import io.openems.common.jsonrpc.request.GetEdgesRequest;
import io.openems.common.jsonrpc.serialization.JsonSerializer;
import io.openems.common.session.Role;
import io.openems.common.types.SemanticVersion;
import io.openems.common.utils.JsonUtils;
Expand Down Expand Up @@ -41,6 +44,36 @@ public record EdgeMetadata(//
Level sumState //
) {

/**
* Returns a {@link JsonSerializer} for a {@link GetEdgesResponse.EdgeMetadata}.
*
* @return the created {@link JsonSerializer}
*/
public static JsonSerializer<GetEdgesResponse.EdgeMetadata> serializer() {
return jsonObjectSerializer(GetEdgesResponse.EdgeMetadata.class, //
json -> new GetEdgesResponse.EdgeMetadata(//
json.getString("id"), //
json.getString("comment"), //
json.getString("producttype"), //
json.getSemanticVersion("version"), //
json.getEnum("role", Role.class), //
json.getBoolean("isOnline"), //
json.getZonedDateTime("lastmessage"), //
json.getZonedDateTimeOrNull("firstSetupProtocol"), //
json.getEnum("sumState", Level.class)),
obj -> JsonUtils.buildJsonObject() //
.addProperty("id", obj.id()) //
.addProperty("comment", obj.comment()) //
.addProperty("producttype", obj.producttype()) //
.addProperty("version", obj.version().toString()) //
.addProperty("role", obj.role()) //
.addProperty("isOnline", obj.isOnline()) //
.addProperty("lastmessage", obj.lastmessage()) //
.addProperty("firstSetupProtocol", obj.firstSetupProtocol()) //
.addProperty("sumState", obj.sumState()) //
.build());
}

/**
* Converts a collection of EdgeMetadatas to a JsonArray.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.openems.common.jsonrpc.serialization;

public interface BooleanPath extends JsonPath {

/**
* Gets the boolean value of the current path.
*
* @return the value
*/
public boolean get();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.openems.common.jsonrpc.serialization;

public final class BooleanPathActual {

public static final class BooleanPathActualNonNull implements BooleanPath {

private final boolean value;

public BooleanPathActualNonNull(boolean value) {
super();
this.value = value;
}

@Override
public boolean get() {
return this.value;
}

}

public static final class BooleanPathActualNullable implements BooleanPathNullable {

private final Boolean value;

public BooleanPathActualNullable(Boolean value) {
super();
this.value = value;
}

@Override
public boolean isPresent() {
return this.value != null;
}

@Override
public Boolean getOrNull() {
return this.value;
}

}

private BooleanPathActual() {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package io.openems.common.jsonrpc.serialization;

import com.google.gson.JsonElement;

public final class BooleanPathDummy {

public static final class BooleanPathDummyNonNull implements BooleanPath, JsonPathDummy {

@Override
public boolean get() {
return false;
}

@Override
public JsonElement buildPath() {
return JsonPrimitivePathDummy.buildPath("boolean", false);
}

}

public static final class BooleanPathDummyNullable implements BooleanPathNullable, JsonPathDummy {

@Override
public boolean isPresent() {
return false;
}

@Override
public Boolean getOrNull() {
return null;
}

@Override
public JsonElement buildPath() {
return JsonPrimitivePathDummy.buildPath("boolean", true);
}

}

private BooleanPathDummy() {
}

}
Loading

0 comments on commit cd0ffd1

Please sign in to comment.