Skip to content

Commit 066d06c

Browse files
tsickingsfeilmeier
andauthored
ElectricityMeter: fix calculateSinglePhaseFromActivePower & calculatePhasesFromReactivePower (OpenEMS#2386)
* Bugfix in SinglePhaseMeter.calculateSinglePhaseFromActivePower * Validate bugfix with JUnit test * Add more JUnit test + fix one more copy&paste error --------- Co-authored-by: Stefan Feilmeier <[email protected]>
1 parent b8ddb8e commit 066d06c

File tree

8 files changed

+583
-13
lines changed

8 files changed

+583
-13
lines changed

io.openems.edge.common/src/io/openems/edge/common/test/TestUtils.java

+33
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
import java.io.IOException;
44
import java.net.ServerSocket;
55

6+
import io.openems.edge.common.channel.Channel;
7+
import io.openems.edge.common.channel.ChannelId;
8+
import io.openems.edge.common.component.OpenemsComponent;
9+
610
public class TestUtils {
711

812
private TestUtils() {
@@ -23,4 +27,33 @@ public static int findRandomOpenPortOnAllLocalInterfaces() throws IOException {
2327
return socket.getLocalPort();
2428
}
2529
}
30+
31+
/**
32+
* Calls {@link Channel#nextProcessImage()} for every Channel of the
33+
* {@link OpenemsComponent}.
34+
*
35+
* @param component the {@link OpenemsComponent}
36+
*/
37+
public static void activateNextProcessImage(OpenemsComponent component) {
38+
component.channels().forEach(channel -> {
39+
channel.nextProcessImage();
40+
});
41+
}
42+
43+
/**
44+
* Sets the value on a Component Channel and activates the Process Image.
45+
*
46+
* <p>
47+
* This is useful to simulate a Channel value in a Unit test, as the value
48+
* becomes directly available on the Channel.
49+
*
50+
* @param component the {@link OpenemsComponent}
51+
* @param channelId the {@link ChannelId}
52+
* @param value the new value
53+
*/
54+
public static void withValue(OpenemsComponent component, ChannelId channelId, Object value) {
55+
var channel = component.channel(channelId);
56+
channel.setNextValue(value);
57+
channel.nextProcessImage();
58+
}
2659
}

io.openems.edge.meter.api/src/io/openems/edge/meter/api/ElectricityMeter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1723,7 +1723,7 @@ public static void calculatePhasesFromReactivePower(ElectricityMeter meter) {
17231723
var phase = TypeUtils.divide(value.get(), 3);
17241724
meter.getReactivePowerL1Channel().setNextValue(phase);
17251725
meter.getReactivePowerL2Channel().setNextValue(phase);
1726-
meter.getReactivePowerL2Channel().setNextValue(phase);
1726+
meter.getReactivePowerL3Channel().setNextValue(phase);
17271727
});
17281728
}
17291729

io.openems.edge.meter.api/src/io/openems/edge/meter/api/SinglePhaseMeter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ public static <METER extends ElectricityMeter> void calculateSinglePhaseFromActi
7272
var phase = phaseProvider.apply(meter);
7373
meter.getActivePowerL1Channel().setNextValue(phase == SinglePhase.L1 ? value : null);
7474
meter.getActivePowerL2Channel().setNextValue(phase == SinglePhase.L2 ? value : null);
75-
meter.getActivePowerL2Channel().setNextValue(phase == SinglePhase.L3 ? value : null);
75+
meter.getActivePowerL3Channel().setNextValue(phase == SinglePhase.L3 ? value : null);
7676
});
7777
}
7878

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
package io.openems.edge.meter.test;
2+
3+
import io.openems.edge.common.channel.Channel;
4+
import io.openems.edge.common.component.AbstractOpenemsComponent;
5+
import io.openems.edge.common.test.TestUtils;
6+
import io.openems.edge.meter.api.ElectricityMeter;
7+
import io.openems.edge.meter.api.MeterType;
8+
9+
public abstract class AbstractDummyElectricityMeter<SELF extends AbstractDummyElectricityMeter<?>>
10+
extends AbstractOpenemsComponent implements ElectricityMeter {
11+
12+
private MeterType meterType;
13+
14+
protected AbstractDummyElectricityMeter(String id,
15+
io.openems.edge.common.channel.ChannelId[] firstInitialChannelIds,
16+
io.openems.edge.common.channel.ChannelId[]... furtherInitialChannelIds) {
17+
super(firstInitialChannelIds, furtherInitialChannelIds);
18+
for (Channel<?> channel : this.channels()) {
19+
channel.nextProcessImage();
20+
}
21+
super.activate(null, id, "", true);
22+
}
23+
24+
protected abstract SELF self();
25+
26+
/**
27+
* Set the {@link MeterType}.
28+
*
29+
* @param meterType the meterType
30+
* @return myself
31+
*/
32+
public SELF withMeterType(MeterType meterType) {
33+
this.meterType = meterType;
34+
return this.self();
35+
}
36+
37+
/**
38+
* Set {@link ElectricityMeter.ChannelId#ACTIVE_POWER} of this
39+
* {@link ElectricityMeter}.
40+
*
41+
* @param value the value
42+
* @return myself
43+
*/
44+
public SELF withActivePower(Integer value) {
45+
TestUtils.withValue(this, ElectricityMeter.ChannelId.ACTIVE_POWER, value);
46+
return this.self();
47+
}
48+
49+
/**
50+
* Set {@link ElectricityMeter.ChannelId#ACTIVE_POWER_L1} of this
51+
* {@link ElectricityMeter}.
52+
*
53+
* @param value the value
54+
* @return myself
55+
*/
56+
public SELF withActivePowerL1(Integer value) {
57+
TestUtils.withValue(this, ElectricityMeter.ChannelId.ACTIVE_POWER_L1, value);
58+
return this.self();
59+
}
60+
61+
/**
62+
* Set {@link ElectricityMeter.ChannelId#ACTIVE_POWER_L2} of this
63+
* {@link ElectricityMeter}.
64+
*
65+
* @param value the value
66+
* @return myself
67+
*/
68+
public SELF withActivePowerL2(Integer value) {
69+
TestUtils.withValue(this, ElectricityMeter.ChannelId.ACTIVE_POWER_L2, value);
70+
return this.self();
71+
}
72+
73+
/**
74+
* Set {@link ElectricityMeter.ChannelId#ACTIVE_POWER_L3} of this
75+
* {@link ElectricityMeter}.
76+
*
77+
* @param value the value
78+
* @return myself
79+
*/
80+
public SELF withActivePowerL3(Integer value) {
81+
TestUtils.withValue(this, ElectricityMeter.ChannelId.ACTIVE_POWER_L3, value);
82+
return this.self();
83+
}
84+
85+
/**
86+
* Set {@link ElectricityMeter.ChannelId#REACTIVE_POWER} of this
87+
* {@link ElectricityMeter}.
88+
*
89+
* @param value the value
90+
* @return myself
91+
*/
92+
public SELF withReactivePower(Integer value) {
93+
TestUtils.withValue(this, ElectricityMeter.ChannelId.REACTIVE_POWER, value);
94+
return this.self();
95+
}
96+
97+
/**
98+
* Set {@link ElectricityMeter.ChannelId#REACTIVE_POWER_L1} of this
99+
* {@link ElectricityMeter}.
100+
*
101+
* @param value the value
102+
* @return myself
103+
*/
104+
public SELF withReactivePowerL1(Integer value) {
105+
TestUtils.withValue(this, ElectricityMeter.ChannelId.REACTIVE_POWER_L1, value);
106+
return this.self();
107+
}
108+
109+
/**
110+
* Set {@link ElectricityMeter.ChannelId#REACTIVE_POWER_L2} of this
111+
* {@link ElectricityMeter}.
112+
*
113+
* @param value the value
114+
* @return myself
115+
*/
116+
public SELF withReactivePowerL2(Integer value) {
117+
TestUtils.withValue(this, ElectricityMeter.ChannelId.REACTIVE_POWER_L2, value);
118+
return this.self();
119+
}
120+
121+
/**
122+
* Set {@link ElectricityMeter.ChannelId#REACTIVE_POWER_L3} of this
123+
* {@link ElectricityMeter}.
124+
*
125+
* @param value the value
126+
* @return myself
127+
*/
128+
public SELF withReactivePowerL3(Integer value) {
129+
TestUtils.withValue(this, ElectricityMeter.ChannelId.REACTIVE_POWER_L3, value);
130+
return this.self();
131+
}
132+
133+
/**
134+
* Set {@link ElectricityMeter.ChannelId#CURRENT} of this
135+
* {@link ElectricityMeter}.
136+
*
137+
* @param value the value
138+
* @return myself
139+
*/
140+
public SELF withCurrent(Integer value) {
141+
TestUtils.withValue(this, ElectricityMeter.ChannelId.CURRENT, value);
142+
return this.self();
143+
}
144+
145+
/**
146+
* Set {@link ElectricityMeter.ChannelId#CURRENT_L1} of this
147+
* {@link ElectricityMeter}.
148+
*
149+
* @param value the value
150+
* @return myself
151+
*/
152+
public SELF withCurrentL1(Integer value) {
153+
TestUtils.withValue(this, ElectricityMeter.ChannelId.CURRENT_L1, value);
154+
return this.self();
155+
}
156+
157+
/**
158+
* Set {@link ElectricityMeter.ChannelId#CURRENT_L2} of this
159+
* {@link ElectricityMeter}.
160+
*
161+
* @param value the value
162+
* @return myself
163+
*/
164+
public SELF withCurrentL2(Integer value) {
165+
TestUtils.withValue(this, ElectricityMeter.ChannelId.CURRENT_L2, value);
166+
return this.self();
167+
}
168+
169+
/**
170+
* Set {@link ElectricityMeter.ChannelId#CURRENT_L3} of this
171+
* {@link ElectricityMeter}.
172+
*
173+
* @param value the value
174+
* @return myself
175+
*/
176+
public SELF withCurrentL3(Integer value) {
177+
TestUtils.withValue(this, ElectricityMeter.ChannelId.CURRENT_L3, value);
178+
return this.self();
179+
}
180+
181+
/**
182+
* Set {@link ElectricityMeter.ChannelId#VOLTAGE} of this
183+
* {@link ElectricityMeter}.
184+
*
185+
* @param value the value
186+
* @return myself
187+
*/
188+
public SELF withVoltage(Integer value) {
189+
TestUtils.withValue(this, ElectricityMeter.ChannelId.VOLTAGE, value);
190+
return this.self();
191+
}
192+
193+
/**
194+
* Set {@link ElectricityMeter.ChannelId#VOLTAGE_L1} of this
195+
* {@link ElectricityMeter}.
196+
*
197+
* @param value the value
198+
* @return myself
199+
*/
200+
public SELF withVoltageL1(Integer value) {
201+
TestUtils.withValue(this, ElectricityMeter.ChannelId.VOLTAGE_L1, value);
202+
return this.self();
203+
}
204+
205+
/**
206+
* Set {@link ElectricityMeter.ChannelId#VOLTAGE_L2} of this
207+
* {@link ElectricityMeter}.
208+
*
209+
* @param value the value
210+
* @return myself
211+
*/
212+
public SELF withVoltageL2(Integer value) {
213+
TestUtils.withValue(this, ElectricityMeter.ChannelId.VOLTAGE_L2, value);
214+
return this.self();
215+
}
216+
217+
/**
218+
* Set {@link ElectricityMeter.ChannelId#VOLTAGE_L3} of this
219+
* {@link ElectricityMeter}.
220+
*
221+
* @param value the value
222+
* @return myself
223+
*/
224+
public SELF withVoltageL3(Integer value) {
225+
TestUtils.withValue(this, ElectricityMeter.ChannelId.VOLTAGE_L3, value);
226+
return this.self();
227+
}
228+
229+
/**
230+
* Set {@link ElectricityMeter.ChannelId#ACTIVE_PRODUCTION_ENERGY} of this
231+
* {@link ElectricityMeter}.
232+
*
233+
* @param value the value
234+
* @return myself
235+
*/
236+
public SELF withActiveProductionEnergy(Integer value) {
237+
TestUtils.withValue(this, ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY, value);
238+
return this.self();
239+
}
240+
241+
/**
242+
* Set {@link ElectricityMeter.ChannelId#ACTIVE_PRODUCTION_ENERGY_L1} of this
243+
* {@link ElectricityMeter}.
244+
*
245+
* @param value the value
246+
* @return myself
247+
*/
248+
public SELF withActiveProductionEnergyL1(Integer value) {
249+
TestUtils.withValue(this, ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY_L1, value);
250+
return this.self();
251+
}
252+
253+
/**
254+
* Set {@link ElectricityMeter.ChannelId#ACTIVE_PRODUCTION_ENERGY_L2} of this
255+
* {@link ElectricityMeter}.
256+
*
257+
* @param value the value
258+
* @return myself
259+
*/
260+
public SELF withActiveProductionEnergyL2(Integer value) {
261+
TestUtils.withValue(this, ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY_L2, value);
262+
return this.self();
263+
}
264+
265+
/**
266+
* Set {@link ElectricityMeter.ChannelId#ACTIVE_PRODUCTION_ENERGY_L3} of this
267+
* {@link ElectricityMeter}.
268+
*
269+
* @param value the value
270+
* @return myself
271+
*/
272+
public SELF withActiveProductionEnergyL3(Integer value) {
273+
TestUtils.withValue(this, ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY_L3, value);
274+
return this.self();
275+
}
276+
277+
@Override
278+
public MeterType getMeterType() {
279+
return this.meterType;
280+
}
281+
282+
}
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,27 @@
11
package io.openems.edge.meter.test;
22

3-
import io.openems.edge.common.channel.Channel;
4-
import io.openems.edge.common.component.AbstractOpenemsComponent;
53
import io.openems.edge.common.component.OpenemsComponent;
64
import io.openems.edge.meter.api.ElectricityMeter;
7-
import io.openems.edge.meter.api.MeterType;
85

96
/**
107
* Provides a simple, simulated ElectricityMeter component that can be used
118
* together with the OpenEMS Component test framework.
129
*/
13-
public class DummyElectricityMeter extends AbstractOpenemsComponent implements ElectricityMeter {
10+
public class DummyElectricityMeter extends AbstractDummyElectricityMeter<DummyElectricityMeter>
11+
implements ElectricityMeter {
1412

1513
public static final int MAX_APPARENT_POWER = 10000;
1614

1715
public DummyElectricityMeter(String id) {
18-
super(//
16+
super(id, //
1917
OpenemsComponent.ChannelId.values(), //
2018
ElectricityMeter.ChannelId.values() //
2119
);
22-
for (Channel<?> channel : this.channels()) {
23-
channel.nextProcessImage();
24-
}
25-
super.activate(null, id, "", true);
2620
}
2721

2822
@Override
29-
public MeterType getMeterType() {
30-
return MeterType.GRID;
23+
protected DummyElectricityMeter self() {
24+
return this;
3125
}
3226

3327
}

0 commit comments

Comments
 (0)