Skip to content

Commit ba8ccdc

Browse files
authored
SunSpec PV-Inverters + Meters: improve implementation (OpenEMS#2231)
Applies to - PV-Inverter.Fronius - PV-Inverter.KACO.blueplanet - PV-Inverter.Kostal - PV-Inverter.SMA.SunnyTripower - SolarEdge.PV-Inverter Improvements: - Set individual phases power, current & voltage, improves compatibility with ElectricityMeter (see OpenEMS#2144) - Evaluate more blocks (= improves device compatibility) - Code cleanup Tested on my private system
1 parent 812afa8 commit ba8ccdc

File tree

3 files changed

+144
-148
lines changed

3 files changed

+144
-148
lines changed

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

+29-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.openems.edge.meter.api;
22

3+
import java.util.function.Function;
4+
35
import org.osgi.annotation.versioning.ProviderType;
46

57
import io.openems.common.channel.AccessMode;
@@ -32,19 +34,42 @@ public Doc doc() {
3234
public SinglePhase getPhase();
3335

3436
/**
35-
* Initializes Channel listeners for a Symmetric {@link ElectricityMeter}.
37+
* Initializes Channel listeners for a {@link SinglePhaseMeter}.
3638
*
3739
* <p>
3840
* Sets the correct value for {@link ChannelId#ACTIVE_POWER_L1},
3941
* {@link ChannelId#ACTIVE_POWER_L2} or {@link ChannelId#ACTIVE_POWER_L3} from
4042
* {@link ChannelId#ACTIVE_POWER} by evaluating the configured
41-
* {@link SinglePhase}.
43+
* {@link SinglePhase} via {@link SinglePhaseMeter#getPhase()}.
4244
*
43-
* @param meter the {@link ElectricityMeter}
45+
* @param meter the {@link SinglePhaseMeter}
4446
*/
4547
public static void calculateSinglePhaseFromActivePower(SinglePhaseMeter meter) {
48+
SinglePhaseMeter.calculateSinglePhaseFromActivePower(meter, SinglePhaseMeter::getPhase);
49+
}
50+
51+
/**
52+
* Initializes Channel listeners for a {@link SinglePhaseMeter}.
53+
*
54+
* <p>
55+
* Use this method if it is not known at compile time, that the
56+
* {@link ElectricityMeter} is a {@link SinglePhaseMeter}, i.e. it is not
57+
* implementing {@link SinglePhaseMeter}.
58+
*
59+
* <p>
60+
* Sets the correct value for {@link ChannelId#ACTIVE_POWER_L1},
61+
* {@link ChannelId#ACTIVE_POWER_L2} or {@link ChannelId#ACTIVE_POWER_L3} from
62+
* {@link ChannelId#ACTIVE_POWER} by evaluating the provided
63+
* {@link SinglePhase}.
64+
*
65+
* @param <METER> type that extends {@link ElectricityMeter}
66+
* @param meter a {@link ElectricityMeter}
67+
* @param phaseProvider a provider for {@link SinglePhase}
68+
*/
69+
public static <METER extends ElectricityMeter> void calculateSinglePhaseFromActivePower(METER meter,
70+
Function<METER, SinglePhase> phaseProvider) {
4671
meter.getActivePowerChannel().onSetNextValue(value -> {
47-
var phase = meter.getPhase();
72+
var phase = phaseProvider.apply(meter);
4873
meter.getActivePowerL1Channel().setNextValue(phase == SinglePhase.L1 ? value : null);
4974
meter.getActivePowerL2Channel().setNextValue(phase == SinglePhase.L2 ? value : null);
5075
meter.getActivePowerL2Channel().setNextValue(phase == SinglePhase.L3 ? value : null);

io.openems.edge.meter.sunspec/src/io/openems/edge/meter/sunspec/AbstractSunSpecMeter.java

+29-57
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515

1616
import io.openems.common.exceptions.OpenemsException;
1717
import io.openems.edge.bridge.modbus.sunspec.AbstractOpenemsSunSpecComponent;
18-
import io.openems.edge.bridge.modbus.sunspec.DefaultSunSpecModel;
18+
import io.openems.edge.bridge.modbus.sunspec.DefaultSunSpecModel.S201;
19+
import io.openems.edge.bridge.modbus.sunspec.DefaultSunSpecModel.S202;
20+
import io.openems.edge.bridge.modbus.sunspec.DefaultSunSpecModel.S203;
21+
import io.openems.edge.bridge.modbus.sunspec.DefaultSunSpecModel.S204;
1922
import io.openems.edge.bridge.modbus.sunspec.SunSpecModel;
2023
import io.openems.edge.bridge.modbus.sunspec.SunSpecPoint;
2124
import io.openems.edge.common.channel.Channel;
@@ -68,135 +71,104 @@ protected void onSunSpecInitializationCompleted() {
6871
this.mapFirstPointToChannel(//
6972
ElectricityMeter.ChannelId.FREQUENCY, //
7073
SCALE_FACTOR_3, //
71-
DefaultSunSpecModel.S204.HZ, DefaultSunSpecModel.S203.HZ, DefaultSunSpecModel.S202.HZ,
72-
DefaultSunSpecModel.S201.HZ);
74+
S204.HZ, S203.HZ, S202.HZ, S201.HZ);
7375
this.mapFirstPointToChannel(//
7476
ElectricityMeter.ChannelId.ACTIVE_POWER, //
7577
INVERT, //
76-
DefaultSunSpecModel.S204.W, DefaultSunSpecModel.S203.W, DefaultSunSpecModel.S202.W,
77-
DefaultSunSpecModel.S201.W);
78+
S204.W, S203.W, S202.W, S201.W);
7879
this.mapFirstPointToChannel(//
7980
ElectricityMeter.ChannelId.REACTIVE_POWER, //
8081
INVERT, //
81-
DefaultSunSpecModel.S204.VAR, DefaultSunSpecModel.S203.VAR, DefaultSunSpecModel.S202.VAR,
82-
DefaultSunSpecModel.S201.VAR);
82+
S204.VAR, S203.VAR, S202.VAR, S201.VAR);
8383
this.mapFirstPointToChannel(//
8484
ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY, //
8585
DIRECT_1_TO_1, //
86-
DefaultSunSpecModel.S204.TOT_WH_EXP, DefaultSunSpecModel.S203.TOT_WH_EXP,
87-
DefaultSunSpecModel.S202.TOT_WH_EXP, DefaultSunSpecModel.S201.TOT_WH_EXP);
86+
S204.TOT_WH_EXP, S203.TOT_WH_EXP, S202.TOT_WH_EXP, S201.TOT_WH_EXP);
8887
this.mapFirstPointToChannel(//
8988
ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY, //
9089
DIRECT_1_TO_1, //
91-
DefaultSunSpecModel.S204.TOT_WH_IMP, DefaultSunSpecModel.S203.TOT_WH_IMP,
92-
DefaultSunSpecModel.S202.TOT_WH_IMP, DefaultSunSpecModel.S201.TOT_WH_IMP);
90+
S204.TOT_WH_IMP, S203.TOT_WH_IMP, S202.TOT_WH_IMP, S201.TOT_WH_IMP);
9391
this.mapFirstPointToChannel(//
9492
ElectricityMeter.ChannelId.VOLTAGE, //
9593
SCALE_FACTOR_3, //
96-
DefaultSunSpecModel.S204.PH_V, DefaultSunSpecModel.S203.PH_V, DefaultSunSpecModel.S202.PH_V,
97-
DefaultSunSpecModel.S201.PH_V, //
98-
DefaultSunSpecModel.S204.PH_VPH_A, DefaultSunSpecModel.S203.PH_VPH_A, DefaultSunSpecModel.S202.PH_VPH_A,
99-
DefaultSunSpecModel.S201.PH_VPH_A, //
100-
DefaultSunSpecModel.S204.PH_VPH_B, DefaultSunSpecModel.S203.PH_VPH_B, DefaultSunSpecModel.S202.PH_VPH_B,
101-
DefaultSunSpecModel.S201.PH_VPH_B, //
102-
DefaultSunSpecModel.S204.PH_VPH_C, DefaultSunSpecModel.S203.PH_VPH_C, DefaultSunSpecModel.S202.PH_VPH_C,
103-
DefaultSunSpecModel.S201.PH_VPH_C);
94+
S204.PH_V, S203.PH_V, S202.PH_V, S201.PH_V);
10495
this.mapFirstPointToChannel(//
10596
ElectricityMeter.ChannelId.CURRENT, //
10697
SCALE_FACTOR_3, //
107-
DefaultSunSpecModel.S204.A, DefaultSunSpecModel.S203.A, DefaultSunSpecModel.S202.A,
108-
DefaultSunSpecModel.S201.A);
98+
S204.A, S203.A, S202.A, S201.A);
10999

110100
this.mapFirstPointToChannel(//
111101
ElectricityMeter.ChannelId.ACTIVE_POWER_L1, //
112102
INVERT, //
113-
DefaultSunSpecModel.S204.WPH_A, DefaultSunSpecModel.S203.WPH_A, DefaultSunSpecModel.S202.WPH_A,
114-
DefaultSunSpecModel.S201.WPH_A);
103+
S204.WPH_A, S203.WPH_A, S202.WPH_A, S201.WPH_A);
115104
this.mapFirstPointToChannel(//
116105
ElectricityMeter.ChannelId.ACTIVE_POWER_L2, //
117106
INVERT, //
118-
DefaultSunSpecModel.S204.WPH_B, DefaultSunSpecModel.S203.WPH_B, DefaultSunSpecModel.S202.WPH_B,
119-
DefaultSunSpecModel.S201.WPH_B);
107+
S204.WPH_B, S203.WPH_B, S202.WPH_B, S201.WPH_B);
120108
this.mapFirstPointToChannel(//
121109
ElectricityMeter.ChannelId.ACTIVE_POWER_L3, //
122110
INVERT, //
123-
DefaultSunSpecModel.S204.WPH_C, DefaultSunSpecModel.S203.WPH_C, DefaultSunSpecModel.S202.WPH_C,
124-
DefaultSunSpecModel.S201.WPH_C);
111+
S204.WPH_C, S203.WPH_C, S202.WPH_C, S201.WPH_C);
125112
this.mapFirstPointToChannel(//
126113
ElectricityMeter.ChannelId.CURRENT_L1, //
127114
SCALE_FACTOR_3, //
128-
DefaultSunSpecModel.S204.APH_A, DefaultSunSpecModel.S203.APH_A, DefaultSunSpecModel.S202.APH_A,
129-
DefaultSunSpecModel.S201.APH_A);
115+
S204.APH_A, S203.APH_A, S202.APH_A, S201.APH_A);
130116
this.mapFirstPointToChannel(//
131117
ElectricityMeter.ChannelId.CURRENT_L2, //
132118
SCALE_FACTOR_3, //
133-
DefaultSunSpecModel.S204.APH_B, DefaultSunSpecModel.S203.APH_B, DefaultSunSpecModel.S202.APH_B,
134-
DefaultSunSpecModel.S201.APH_B);
119+
S204.APH_B, S203.APH_B, S202.APH_B, S201.APH_B);
135120
this.mapFirstPointToChannel(//
136121
ElectricityMeter.ChannelId.CURRENT_L3, //
137122
SCALE_FACTOR_3, //
138-
DefaultSunSpecModel.S204.APH_C, DefaultSunSpecModel.S203.APH_C, DefaultSunSpecModel.S202.APH_C,
139-
DefaultSunSpecModel.S201.APH_C);
123+
S204.APH_C, S203.APH_C, S202.APH_C, S201.APH_C);
140124
this.mapFirstPointToChannel(//
141125
ElectricityMeter.ChannelId.REACTIVE_POWER_L1, //
142126
INVERT, //
143-
DefaultSunSpecModel.S204.V_A_RPH_A, DefaultSunSpecModel.S203.V_A_RPH_A,
144-
DefaultSunSpecModel.S202.V_A_RPH_A, DefaultSunSpecModel.S201.V_A_RPH_A);
127+
S204.V_A_RPH_A, S203.V_A_RPH_A, S202.V_A_RPH_A, S201.V_A_RPH_A);
145128
this.mapFirstPointToChannel(//
146129
ElectricityMeter.ChannelId.REACTIVE_POWER_L2, //
147130
INVERT, //
148-
DefaultSunSpecModel.S204.V_A_RPH_B, DefaultSunSpecModel.S203.V_A_RPH_B,
149-
DefaultSunSpecModel.S202.V_A_RPH_B, DefaultSunSpecModel.S201.V_A_RPH_B);
131+
S204.V_A_RPH_B, S203.V_A_RPH_B, S202.V_A_RPH_B, S201.V_A_RPH_B);
150132
this.mapFirstPointToChannel(//
151133
ElectricityMeter.ChannelId.REACTIVE_POWER_L3, //
152134
INVERT, //
153-
DefaultSunSpecModel.S204.V_A_RPH_C, DefaultSunSpecModel.S203.V_A_RPH_C,
154-
DefaultSunSpecModel.S202.V_A_RPH_C, DefaultSunSpecModel.S201.V_A_RPH_C);
135+
S204.V_A_RPH_C, S203.V_A_RPH_C, S202.V_A_RPH_C, S201.V_A_RPH_C);
155136
this.mapFirstPointToChannel(//
156137
ElectricityMeter.ChannelId.VOLTAGE_L1, //
157138
SCALE_FACTOR_3, //
158-
DefaultSunSpecModel.S204.PH_VPH_A, DefaultSunSpecModel.S203.PH_VPH_A, DefaultSunSpecModel.S202.PH_VPH_A,
159-
DefaultSunSpecModel.S201.PH_VPH_A);
139+
S204.PH_VPH_A, S203.PH_VPH_A, S202.PH_VPH_A, S201.PH_VPH_A);
160140
this.mapFirstPointToChannel(//
161141
ElectricityMeter.ChannelId.VOLTAGE_L2, //
162142
SCALE_FACTOR_3, //
163-
DefaultSunSpecModel.S204.PH_VPH_B, DefaultSunSpecModel.S203.PH_VPH_B, DefaultSunSpecModel.S202.PH_VPH_B,
164-
DefaultSunSpecModel.S201.PH_VPH_B);
143+
S204.PH_VPH_B, S203.PH_VPH_B, S202.PH_VPH_B, S201.PH_VPH_B);
165144
this.mapFirstPointToChannel(//
166145
ElectricityMeter.ChannelId.VOLTAGE_L3, //
167146
SCALE_FACTOR_3, //
168-
DefaultSunSpecModel.S204.PH_VPH_C, DefaultSunSpecModel.S203.PH_VPH_C, DefaultSunSpecModel.S202.PH_VPH_C,
169-
DefaultSunSpecModel.S201.PH_VPH_C);
147+
S204.PH_VPH_C, S203.PH_VPH_C, S202.PH_VPH_C, S201.PH_VPH_C);
170148
this.mapFirstPointToChannel(//
171149
ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY_L1, //
172150
DIRECT_1_TO_1, //
173-
DefaultSunSpecModel.S204.TOT_WH_EXP_PH_A, DefaultSunSpecModel.S203.TOT_WH_EXP_PH_A,
174-
DefaultSunSpecModel.S202.TOT_WH_EXP_PH_A, DefaultSunSpecModel.S201.TOT_WH_EXP_PH_A);
151+
S204.TOT_WH_EXP_PH_A, S203.TOT_WH_EXP_PH_A, S202.TOT_WH_EXP_PH_A, S201.TOT_WH_EXP_PH_A);
175152
this.mapFirstPointToChannel(//
176153
ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY_L2, //
177154
DIRECT_1_TO_1, //
178-
DefaultSunSpecModel.S204.TOT_WH_EXP_PH_B, DefaultSunSpecModel.S203.TOT_WH_EXP_PH_B,
179-
DefaultSunSpecModel.S202.TOT_WH_EXP_PH_B, DefaultSunSpecModel.S201.TOT_WH_EXP_PH_B);
155+
S204.TOT_WH_EXP_PH_B, S203.TOT_WH_EXP_PH_B, S202.TOT_WH_EXP_PH_B, S201.TOT_WH_EXP_PH_B);
180156
this.mapFirstPointToChannel(//
181157
ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY_L3, //
182158
DIRECT_1_TO_1, //
183-
DefaultSunSpecModel.S204.TOT_WH_EXP_PH_C, DefaultSunSpecModel.S203.TOT_WH_EXP_PH_C,
184-
DefaultSunSpecModel.S202.TOT_WH_EXP_PH_C, DefaultSunSpecModel.S201.TOT_WH_EXP_PH_C);
159+
S204.TOT_WH_EXP_PH_C, S203.TOT_WH_EXP_PH_C, S202.TOT_WH_EXP_PH_C, S201.TOT_WH_EXP_PH_C);
185160
this.mapFirstPointToChannel(//
186161
ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY_L1, //
187162
DIRECT_1_TO_1, //
188-
DefaultSunSpecModel.S204.TOT_WH_IMP_PH_A, DefaultSunSpecModel.S203.TOT_WH_IMP_PH_A,
189-
DefaultSunSpecModel.S202.TOT_WH_IMP_PH_A, DefaultSunSpecModel.S201.TOT_WH_IMP_PH_A);
163+
S204.TOT_WH_IMP_PH_A, S203.TOT_WH_IMP_PH_A, S202.TOT_WH_IMP_PH_A, S201.TOT_WH_IMP_PH_A);
190164
this.mapFirstPointToChannel(//
191165
ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY_L2, //
192166
DIRECT_1_TO_1, //
193-
DefaultSunSpecModel.S204.TOT_WH_IMP_PH_B, DefaultSunSpecModel.S203.TOT_WH_IMP_PH_B,
194-
DefaultSunSpecModel.S202.TOT_WH_IMP_PH_B, DefaultSunSpecModel.S201.TOT_WH_IMP_PH_B);
167+
S204.TOT_WH_IMP_PH_B, S203.TOT_WH_IMP_PH_B, S202.TOT_WH_IMP_PH_B, S201.TOT_WH_IMP_PH_B);
195168
this.mapFirstPointToChannel(//
196169
ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY_L3, //
197170
DIRECT_1_TO_1, //
198-
DefaultSunSpecModel.S204.TOT_WH_IMP_PH_C, DefaultSunSpecModel.S203.TOT_WH_IMP_PH_C,
199-
DefaultSunSpecModel.S202.TOT_WH_IMP_PH_C, DefaultSunSpecModel.S201.TOT_WH_IMP_PH_C);
171+
S204.TOT_WH_IMP_PH_C, S203.TOT_WH_IMP_PH_C, S202.TOT_WH_IMP_PH_C, S201.TOT_WH_IMP_PH_C);
200172
}
201173

202174
@Override

0 commit comments

Comments
 (0)