Skip to content

Commit b0dff31

Browse files
authored
split TimestampedDatanotification into AggregatedDataNotification, TimestampedDataNotification and ResendDataNotification. Added/enhanced some utilities classes. (OpenEMS#2297)
Thank you for providing us your code and for review.
1 parent a37da1a commit b0dff31

9 files changed

+482
-64
lines changed

io.openems.common/src/io/openems/common/channel/PersistencePriority.java

+75
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,86 @@
11
package io.openems.common.channel;
22

3+
import io.openems.common.jsonrpc.notification.AggregatedDataNotification;
4+
import io.openems.common.jsonrpc.notification.TimestampedDataNotification;
5+
6+
/**
7+
* The {@link PersistencePriority} is used by...
8+
*
9+
* <ul>
10+
* <li>Timedata.Rrd4j: persist Channel values locally
11+
* <li>Controller.Api.MQTT: transmit Channel values via MQTT
12+
* <li>Controller.Api.Backend: transmit Channel values to OpenEMS Backend
13+
* </ul>
14+
*
15+
* <p>
16+
* These services use the {@link PersistencePriority} to distinguish whether a
17+
* value of a Channel should be:
18+
* <ul>
19+
* <li>persisted/transmitted in high resolution (e.g. once per second)
20+
* <li>persisted/transmitted in low resolution (e.g. aggregated to 5 minutes
21+
* values)
22+
* <li>not persisted
23+
* </ul>
24+
*
25+
* <p>
26+
* The {@link PersistencePriority} of a Channel may be set via
27+
* AbstractDoc::persistencePriority(). Defaults are:
28+
* <ul>
29+
* <li>{@link #HIGH} for StateChannels
30+
* <li>{@link #LOW} for everything else
31+
* </ul>
32+
*/
333
public enum PersistencePriority {
434

35+
/**
36+
* Channels with at least this priority are by default (if not configured
37+
* differently)...
38+
*
39+
* <ul>
40+
* <li>Timedata.Rrd4j: not persisted
41+
* <li>Controller.Api.MQTT: transmitted in high resolution
42+
* <li>Controller.Api.Backend: not transmitted
43+
* </ul>
44+
*/
545
VERY_LOW(0), //
46+
47+
/**
48+
* Channels with at least this priority are by default (if not configured
49+
* differently)...
50+
*
51+
* <ul>
52+
* <li>Controller.Api.Backend: transmitted as aggregated values (via
53+
* {@link AggregatedDataNotification})
54+
* </ul>
55+
*/
656
LOW(1), //
57+
58+
/**
59+
* Channels with at least this priority are by default (if not configured
60+
* differently)...
61+
*
62+
* <ul>
63+
* <li>Timedata.Rrd4j: persisted as aggregated values
64+
* </ul>
65+
*/
766
MEDIUM(2), //
67+
68+
/**
69+
* Channels with at least this priority are by default (if not configured
70+
* differently)...
71+
*
72+
* <ul>
73+
* <li>Controller.Api.Backend: transmitted in high resolution (via
74+
* {@link TimestampedDataNotification}), i.e. on every change or at least once
75+
* every 5 minutes
76+
* </ul>
77+
*/
878
HIGH(3), //
79+
80+
/**
81+
* {@link PersistencePriority#VERY_HIGH} is reserved for Channels of the
82+
* `Core.Sum` Component.
83+
*/
984
VERY_HIGH(4), //
1085
;
1186

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package io.openems.common.function;
2+
3+
/**
4+
* This interface is similar to the java.util interface
5+
* {@link ThrowingBiConsumer}. Difference is, that it allows to pass to the
6+
* apply() method one more parameter.
7+
*
8+
* @param <T> the apply methods first argument type
9+
* @param <U> the apply methods second argument type
10+
* @param <S> the apply methods third argument type
11+
* @param <E> the exception type
12+
*/
13+
@FunctionalInterface
14+
public interface ThrowingTriConsumer<T, U, S, E extends Exception> {
15+
16+
/**
17+
* Applies this function to the given arguments.
18+
*
19+
* @param t the first function argument
20+
* @param u the second function argument
21+
* @param s the third function argument
22+
* @throws E on error
23+
*/
24+
public void accept(T t, U u, S s) throws E;
25+
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package io.openems.common.jsonrpc.notification;
2+
3+
import java.util.Map;
4+
5+
import com.google.common.collect.TreeBasedTable;
6+
import com.google.gson.JsonElement;
7+
import com.google.gson.JsonObject;
8+
9+
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
10+
import io.openems.common.jsonrpc.base.JsonrpcNotification;
11+
import io.openems.common.utils.JsonUtils;
12+
13+
/**
14+
* Represents a JSON-RPC Notification for timestamped or aggregated data sent
15+
* from Edge to Backend.
16+
*
17+
* <pre>
18+
* {
19+
* "jsonrpc": "2.0",
20+
* "method": "timestampedData | aggregatedData",
21+
* "params": {
22+
* [timestamp: epoch in milliseconds]: {
23+
* [channelAddress]: T
24+
* }
25+
* }
26+
* }
27+
* </pre>
28+
*/
29+
// TODO change to sealed class
30+
public abstract class AbstractDataNotification extends JsonrpcNotification {
31+
32+
private final TreeBasedTable<Long, String, JsonElement> data;
33+
34+
protected static TreeBasedTable<Long, String, JsonElement> parseParams(//
35+
final JsonObject params //
36+
) throws OpenemsNamedException {
37+
var data = TreeBasedTable.<Long, String, JsonElement>create();
38+
for (var e1 : params.entrySet()) {
39+
var timestamp = Long.parseLong(e1.getKey());
40+
var jTime = JsonUtils.getAsJsonObject(e1.getValue());
41+
for (var e2 : jTime.entrySet()) {
42+
data.put(timestamp, e2.getKey(), e2.getValue());
43+
}
44+
}
45+
return data;
46+
}
47+
48+
protected AbstractDataNotification(String method, TreeBasedTable<Long, String, JsonElement> data) {
49+
super(method);
50+
this.data = data;
51+
}
52+
53+
/**
54+
* Add timestamped data.
55+
*
56+
* @param timestamp the timestamp epoch in milliseconds
57+
* @param data a map of Channel-Address to {@link JsonElement} value
58+
*/
59+
public void add(long timestamp, Map<String, JsonElement> data) {
60+
for (var entry : data.entrySet()) {
61+
this.add(timestamp, entry.getKey(), entry.getValue());
62+
}
63+
}
64+
65+
/**
66+
* Add a timestamped value.
67+
*
68+
* @param timestamp the timestamp epoch in milliseconds
69+
* @param address the Channel-Address
70+
* @param value the {@link JsonElement} value
71+
*/
72+
public void add(long timestamp, String address, JsonElement value) {
73+
this.data.put(timestamp, address, value);
74+
}
75+
76+
@Override
77+
public JsonObject getParams() {
78+
var p = new JsonObject();
79+
for (var e1 : this.data.rowMap().entrySet()) {
80+
var jTime = new JsonObject();
81+
for (var e2 : e1.getValue().entrySet()) {
82+
var address = e2.getKey();
83+
var value = e2.getValue();
84+
jTime.add(address, value);
85+
}
86+
p.add(e1.getKey().toString(), jTime);
87+
}
88+
return p;
89+
}
90+
91+
public TreeBasedTable<Long, String, JsonElement> getData() {
92+
return this.data;
93+
}
94+
95+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package io.openems.common.jsonrpc.notification;
2+
3+
import com.google.common.collect.TreeBasedTable;
4+
import com.google.gson.JsonElement;
5+
6+
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
7+
import io.openems.common.jsonrpc.base.JsonrpcNotification;
8+
9+
/**
10+
* Represents a JSON-RPC Notification for aggregatedData data sent from Edge to
11+
* Backend.
12+
*
13+
* <pre>
14+
* {
15+
* "jsonrpc": "2.0",
16+
* "method": "aggregatedData",
17+
* "params": {
18+
* [timestamp: epoch in milliseconds]: {
19+
* [channelAddress]: {@link JsonElement}
20+
* }
21+
* }
22+
* }
23+
* </pre>
24+
*/
25+
public class AggregatedDataNotification extends AbstractDataNotification {
26+
27+
public static final String METHOD = "aggregatedData";
28+
29+
/**
30+
* Parses a {@link JsonrpcNotification} to a {@link AggregatedDataNotification}.
31+
*
32+
* @param notification the {@link JsonrpcNotification}
33+
* @return the {@link AggregatedDataNotification}
34+
* @throws OpenemsNamedException on error
35+
*/
36+
public static AggregatedDataNotification from(JsonrpcNotification notification) throws OpenemsNamedException {
37+
return new AggregatedDataNotification(parseParams(notification.getParams()));
38+
}
39+
40+
public AggregatedDataNotification(TreeBasedTable<Long, String, JsonElement> data) {
41+
super(AggregatedDataNotification.METHOD, data);
42+
}
43+
44+
public AggregatedDataNotification() {
45+
super(AggregatedDataNotification.METHOD, TreeBasedTable.create());
46+
}
47+
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package io.openems.common.jsonrpc.notification;
2+
3+
import com.google.common.collect.TreeBasedTable;
4+
import com.google.gson.JsonElement;
5+
6+
import io.openems.common.exceptions.OpenemsError.OpenemsNamedException;
7+
import io.openems.common.jsonrpc.base.JsonrpcNotification;
8+
9+
/**
10+
* Represents a JSON-RPC Notification for resending aggregated data.
11+
*
12+
* <pre>
13+
* {
14+
* "jsonrpc": "2.0",
15+
* "method": "resendData",
16+
* "params": {
17+
* [channelAddress]: string | number
18+
* }
19+
* }
20+
* </pre>
21+
*/
22+
public class ResendDataNotification extends AbstractDataNotification {
23+
24+
public static final String METHOD = "resendData";
25+
26+
/**
27+
* Parses a {@link JsonrpcNotification} to a {@link ResendDataNotification}.
28+
*
29+
* @param notification the {@link JsonrpcNotification}
30+
* @return the {@link ResendDataNotification}
31+
* @throws OpenemsNamedException on error
32+
*/
33+
public static ResendDataNotification from(JsonrpcNotification notification) throws OpenemsNamedException {
34+
return new ResendDataNotification(parseParams(notification.getParams()));
35+
}
36+
37+
public ResendDataNotification(TreeBasedTable<Long, String, JsonElement> data) {
38+
super(ResendDataNotification.METHOD, data);
39+
}
40+
41+
}

0 commit comments

Comments
 (0)