Skip to content

Commit

Permalink
split TimestampedDatanotification into AggregatedDataNotification, Ti…
Browse files Browse the repository at this point in the history
…mestampedDataNotification and ResendDataNotification. Added/enhanced some utilities classes. (#2297)

Thank you for providing us your code and for review.
  • Loading branch information
clehne authored Aug 3, 2023
1 parent a37da1a commit b0dff31
Show file tree
Hide file tree
Showing 9 changed files with 482 additions and 64 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,86 @@
package io.openems.common.channel;

import io.openems.common.jsonrpc.notification.AggregatedDataNotification;
import io.openems.common.jsonrpc.notification.TimestampedDataNotification;

/**
* The {@link PersistencePriority} is used by...
*
* <ul>
* <li>Timedata.Rrd4j: persist Channel values locally
* <li>Controller.Api.MQTT: transmit Channel values via MQTT
* <li>Controller.Api.Backend: transmit Channel values to OpenEMS Backend
* </ul>
*
* <p>
* These services use the {@link PersistencePriority} to distinguish whether a
* value of a Channel should be:
* <ul>
* <li>persisted/transmitted in high resolution (e.g. once per second)
* <li>persisted/transmitted in low resolution (e.g. aggregated to 5 minutes
* values)
* <li>not persisted
* </ul>
*
* <p>
* The {@link PersistencePriority} of a Channel may be set via
* AbstractDoc::persistencePriority(). Defaults are:
* <ul>
* <li>{@link #HIGH} for StateChannels
* <li>{@link #LOW} for everything else
* </ul>
*/
public enum PersistencePriority {

/**
* Channels with at least this priority are by default (if not configured
* differently)...
*
* <ul>
* <li>Timedata.Rrd4j: not persisted
* <li>Controller.Api.MQTT: transmitted in high resolution
* <li>Controller.Api.Backend: not transmitted
* </ul>
*/
VERY_LOW(0), //

/**
* Channels with at least this priority are by default (if not configured
* differently)...
*
* <ul>
* <li>Controller.Api.Backend: transmitted as aggregated values (via
* {@link AggregatedDataNotification})
* </ul>
*/
LOW(1), //

/**
* Channels with at least this priority are by default (if not configured
* differently)...
*
* <ul>
* <li>Timedata.Rrd4j: persisted as aggregated values
* </ul>
*/
MEDIUM(2), //

/**
* Channels with at least this priority are by default (if not configured
* differently)...
*
* <ul>
* <li>Controller.Api.Backend: transmitted in high resolution (via
* {@link TimestampedDataNotification}), i.e. on every change or at least once
* every 5 minutes
* </ul>
*/
HIGH(3), //

/**
* {@link PersistencePriority#VERY_HIGH} is reserved for Channels of the
* `Core.Sum` Component.
*/
VERY_HIGH(4), //
;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.openems.common.function;

/**
* This interface is similar to the java.util interface
* {@link ThrowingBiConsumer}. Difference is, that it allows to pass to the
* apply() method one more parameter.
*
* @param <T> the apply methods first argument type
* @param <U> the apply methods second argument type
* @param <S> the apply methods third argument type
* @param <E> the exception type
*/
@FunctionalInterface
public interface ThrowingTriConsumer<T, U, S, E extends Exception> {

/**
* Applies this function to the given arguments.
*
* @param t the first function argument
* @param u the second function argument
* @param s the third function argument
* @throws E on error
*/
public void accept(T t, U u, S s) throws E;

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

import java.util.Map;

import com.google.common.collect.TreeBasedTable;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.common.jsonrpc.base.JsonrpcNotification;
import io.openems.common.utils.JsonUtils;

/**
* Represents a JSON-RPC Notification for timestamped or aggregated data sent
* from Edge to Backend.
*
* <pre>
* {
* "jsonrpc": "2.0",
* "method": "timestampedData | aggregatedData",
* "params": {
* [timestamp: epoch in milliseconds]: {
* [channelAddress]: T
* }
* }
* }
* </pre>
*/
// TODO change to sealed class
public abstract class AbstractDataNotification extends JsonrpcNotification {

private final TreeBasedTable<Long, String, JsonElement> data;

protected static TreeBasedTable<Long, String, JsonElement> parseParams(//
final JsonObject params //
) throws OpenemsNamedException {
var data = TreeBasedTable.<Long, String, JsonElement>create();
for (var e1 : params.entrySet()) {
var timestamp = Long.parseLong(e1.getKey());
var jTime = JsonUtils.getAsJsonObject(e1.getValue());
for (var e2 : jTime.entrySet()) {
data.put(timestamp, e2.getKey(), e2.getValue());
}
}
return data;
}

protected AbstractDataNotification(String method, TreeBasedTable<Long, String, JsonElement> data) {
super(method);
this.data = data;
}

/**
* Add timestamped data.
*
* @param timestamp the timestamp epoch in milliseconds
* @param data a map of Channel-Address to {@link JsonElement} value
*/
public void add(long timestamp, Map<String, JsonElement> data) {
for (var entry : data.entrySet()) {
this.add(timestamp, entry.getKey(), entry.getValue());
}
}

/**
* Add a timestamped value.
*
* @param timestamp the timestamp epoch in milliseconds
* @param address the Channel-Address
* @param value the {@link JsonElement} value
*/
public void add(long timestamp, String address, JsonElement value) {
this.data.put(timestamp, address, value);
}

@Override
public JsonObject getParams() {
var p = new JsonObject();
for (var e1 : this.data.rowMap().entrySet()) {
var jTime = new JsonObject();
for (var e2 : e1.getValue().entrySet()) {
var address = e2.getKey();
var value = e2.getValue();
jTime.add(address, value);
}
p.add(e1.getKey().toString(), jTime);
}
return p;
}

public TreeBasedTable<Long, String, JsonElement> getData() {
return this.data;
}

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

import com.google.common.collect.TreeBasedTable;
import com.google.gson.JsonElement;

import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.common.jsonrpc.base.JsonrpcNotification;

/**
* Represents a JSON-RPC Notification for aggregatedData data sent from Edge to
* Backend.
*
* <pre>
* {
* "jsonrpc": "2.0",
* "method": "aggregatedData",
* "params": {
* [timestamp: epoch in milliseconds]: {
* [channelAddress]: {@link JsonElement}
* }
* }
* }
* </pre>
*/
public class AggregatedDataNotification extends AbstractDataNotification {

public static final String METHOD = "aggregatedData";

/**
* Parses a {@link JsonrpcNotification} to a {@link AggregatedDataNotification}.
*
* @param notification the {@link JsonrpcNotification}
* @return the {@link AggregatedDataNotification}
* @throws OpenemsNamedException on error
*/
public static AggregatedDataNotification from(JsonrpcNotification notification) throws OpenemsNamedException {
return new AggregatedDataNotification(parseParams(notification.getParams()));
}

public AggregatedDataNotification(TreeBasedTable<Long, String, JsonElement> data) {
super(AggregatedDataNotification.METHOD, data);
}

public AggregatedDataNotification() {
super(AggregatedDataNotification.METHOD, TreeBasedTable.create());
}

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

import com.google.common.collect.TreeBasedTable;
import com.google.gson.JsonElement;

import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
import io.openems.common.jsonrpc.base.JsonrpcNotification;

/**
* Represents a JSON-RPC Notification for resending aggregated data.
*
* <pre>
* {
* "jsonrpc": "2.0",
* "method": "resendData",
* "params": {
* [channelAddress]: string | number
* }
* }
* </pre>
*/
public class ResendDataNotification extends AbstractDataNotification {

public static final String METHOD = "resendData";

/**
* Parses a {@link JsonrpcNotification} to a {@link ResendDataNotification}.
*
* @param notification the {@link JsonrpcNotification}
* @return the {@link ResendDataNotification}
* @throws OpenemsNamedException on error
*/
public static ResendDataNotification from(JsonrpcNotification notification) throws OpenemsNamedException {
return new ResendDataNotification(parseParams(notification.getParams()));
}

public ResendDataNotification(TreeBasedTable<Long, String, JsonElement> data) {
super(ResendDataNotification.METHOD, data);
}

}
Loading

0 comments on commit b0dff31

Please sign in to comment.