diff --git a/io.openems.edge.application/EdgeApp.bndrun b/io.openems.edge.application/EdgeApp.bndrun
index 6a9d772129a..431e7506b79 100644
--- a/io.openems.edge.application/EdgeApp.bndrun
+++ b/io.openems.edge.application/EdgeApp.bndrun
@@ -171,6 +171,7 @@
bnd.identity;id='io.openems.edge.meter.discovergy',\
bnd.identity;id='io.openems.edge.meter.eastron',\
bnd.identity;id='io.openems.edge.meter.hager',\
+ bnd.identity;id='io.openems.edge.meter.inepro',\
bnd.identity;id='io.openems.edge.meter.janitza',\
bnd.identity;id='io.openems.edge.meter.kdk',\
bnd.identity;id='io.openems.edge.meter.phoenixcontact',\
@@ -377,6 +378,7 @@
io.openems.edge.meter.discovergy;version=snapshot,\
io.openems.edge.meter.eastron;version=snapshot,\
io.openems.edge.meter.hager;version=snapshot,\
+ io.openems.edge.meter.inepro;version=snapshot,\
io.openems.edge.meter.janitza;version=snapshot,\
io.openems.edge.meter.kdk;version=snapshot,\
io.openems.edge.meter.phoenixcontact;version=snapshot,\
diff --git a/io.openems.edge.meter.inepro/.classpath b/io.openems.edge.meter.inepro/.classpath
new file mode 100644
index 00000000000..b4cffd0fe60
--- /dev/null
+++ b/io.openems.edge.meter.inepro/.classpath
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/io.openems.edge.meter.inepro/.gitignore b/io.openems.edge.meter.inepro/.gitignore
new file mode 100644
index 00000000000..c2b941a96de
--- /dev/null
+++ b/io.openems.edge.meter.inepro/.gitignore
@@ -0,0 +1,2 @@
+/bin_test/
+/generated/
diff --git a/io.openems.edge.meter.inepro/.project b/io.openems.edge.meter.inepro/.project
new file mode 100755
index 00000000000..6fad8cf20de
--- /dev/null
+++ b/io.openems.edge.meter.inepro/.project
@@ -0,0 +1,23 @@
+
+
+ io.openems.edge.meter.inepro
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ bndtools.core.bndbuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+ bndtools.core.bndnature
+
+
diff --git a/io.openems.edge.meter.inepro/.settings/org.eclipse.core.resources.prefs b/io.openems.edge.meter.inepro/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000000..99f26c0203a
--- /dev/null
+++ b/io.openems.edge.meter.inepro/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
diff --git a/io.openems.edge.meter.inepro/bnd.bnd b/io.openems.edge.meter.inepro/bnd.bnd
new file mode 100644
index 00000000000..92c806b77e4
--- /dev/null
+++ b/io.openems.edge.meter.inepro/bnd.bnd
@@ -0,0 +1,16 @@
+Bundle-Name: OpenEMS Edge io.openems.edge.meter.inepro
+Bundle-Vendor: VEV Platform Services France
+Bundle-License: https://opensource.org/licenses/EPL-2.0
+Bundle-Version: 1.0.0.${tstamp}
+
+-buildpath: \
+ ${buildpath},\
+ io.openems.common,\
+ io.openems.edge.bridge.modbus,\
+ io.openems.edge.common,\
+ io.openems.edge.meter.api,\
+ io.openems.j2mod,\
+
+-testpath: \
+ ${testpath},\
+ io.openems.common
diff --git a/io.openems.edge.meter.inepro/doc/pro380modct-modbus.pdf b/io.openems.edge.meter.inepro/doc/pro380modct-modbus.pdf
new file mode 100644
index 00000000000..a13a3952f66
Binary files /dev/null and b/io.openems.edge.meter.inepro/doc/pro380modct-modbus.pdf differ
diff --git a/io.openems.edge.meter.inepro/src/io/openems/edge/meter/inepro/pro380modct/Config.java b/io.openems.edge.meter.inepro/src/io/openems/edge/meter/inepro/pro380modct/Config.java
new file mode 100755
index 00000000000..365e2140ef0
--- /dev/null
+++ b/io.openems.edge.meter.inepro/src/io/openems/edge/meter/inepro/pro380modct/Config.java
@@ -0,0 +1,38 @@
+package io.openems.edge.meter.inepro.pro380modct;
+
+import org.osgi.service.metatype.annotations.AttributeDefinition;
+import org.osgi.service.metatype.annotations.ObjectClassDefinition;
+
+import io.openems.common.types.MeterType;
+
+@ObjectClassDefinition(//
+ name = "Meter inepro Pro380ModCT", //
+ description = "Implements the inepro Pro380ModCT meter.")
+public @interface Config {
+
+ @AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component")
+ String id() default "meter0";
+
+ @AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID")
+ String alias() default "";
+
+ @AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?")
+ boolean enabled() default true;
+
+ @AttributeDefinition(name = "Modbus-ID", description = "ID of Modbus bridge.")
+ String modbus_id() default "modbus0";
+
+ @AttributeDefinition(name = "Modbus Unit-ID", description = "The Unit-ID of the Modbus device.")
+ int modbusUnitId() default 1;
+
+ @AttributeDefinition(name = "Meter-Type", description = "What is measured by this Meter?")
+ MeterType type() default MeterType.CONSUMPTION_METERED;
+
+ @AttributeDefinition(name = "Invert Power", description = "Inverts ALL Power values, inverts current values, swaps production and consumption energy, i.e. Power is multiplied with -1.")
+ boolean invert() default false;
+
+ @AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.")
+ String Modbus_target() default "(enabled=true)";
+
+ String webconsole_configurationFactory_nameHint() default "Meter.inepro.Pro380ModCT [{id}]";
+}
\ No newline at end of file
diff --git a/io.openems.edge.meter.inepro/src/io/openems/edge/meter/inepro/pro380modct/Pro380modct.java b/io.openems.edge.meter.inepro/src/io/openems/edge/meter/inepro/pro380modct/Pro380modct.java
new file mode 100755
index 00000000000..59d3842ac91
--- /dev/null
+++ b/io.openems.edge.meter.inepro/src/io/openems/edge/meter/inepro/pro380modct/Pro380modct.java
@@ -0,0 +1,34 @@
+package io.openems.edge.meter.inepro.pro380modct;
+
+import io.openems.common.channel.Unit;
+import io.openems.common.types.OpenemsType;
+import io.openems.edge.common.channel.Doc;
+import io.openems.edge.common.component.OpenemsComponent;
+import io.openems.edge.common.modbusslave.ModbusSlave;
+import io.openems.edge.meter.api.ElectricityMeter;
+
+public interface Pro380modct extends ElectricityMeter, OpenemsComponent, ModbusSlave {
+
+ public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
+ APPARENT_POWER_L1(Doc.of(OpenemsType.INTEGER)//
+ .unit(Unit.VOLT_AMPERE)), //
+ APPARENT_POWER_L2(Doc.of(OpenemsType.INTEGER)//
+ .unit(Unit.VOLT_AMPERE)), //
+ APPARENT_POWER_L3(Doc.of(OpenemsType.INTEGER)//
+ .unit(Unit.VOLT_AMPERE)), //
+ APPARENT_POWER(Doc.of(OpenemsType.INTEGER)//
+ .unit(Unit.VOLT_AMPERE));
+
+ private final Doc doc;
+
+ private ChannelId(Doc doc) {
+ this.doc = doc;
+ }
+
+ @Override
+ public Doc doc() {
+ return this.doc;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/io.openems.edge.meter.inepro/src/io/openems/edge/meter/inepro/pro380modct/Pro380modctImpl.java b/io.openems.edge.meter.inepro/src/io/openems/edge/meter/inepro/pro380modct/Pro380modctImpl.java
new file mode 100755
index 00000000000..5c13c65e061
--- /dev/null
+++ b/io.openems.edge.meter.inepro/src/io/openems/edge/meter/inepro/pro380modct/Pro380modctImpl.java
@@ -0,0 +1,229 @@
+package io.openems.edge.meter.inepro.pro380modct;
+
+import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_3;
+import static io.openems.edge.bridge.modbus.api.ElementToChannelConverter.SCALE_FACTOR_3_AND_INVERT_IF_TRUE;
+
+import io.openems.common.exceptions.OpenemsException;
+import io.openems.common.types.MeterType;
+import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent;
+import io.openems.edge.bridge.modbus.api.BridgeModbus;
+import io.openems.edge.bridge.modbus.api.ModbusComponent;
+import io.openems.edge.bridge.modbus.api.ModbusProtocol;
+import io.openems.edge.bridge.modbus.api.element.DummyRegisterElement;
+import io.openems.edge.bridge.modbus.api.element.FloatDoublewordElement;
+import io.openems.edge.bridge.modbus.api.element.WordOrder;
+import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask;
+import io.openems.common.channel.AccessMode;
+import io.openems.edge.common.component.OpenemsComponent;
+import io.openems.edge.common.modbusslave.ModbusSlaveNatureTable;
+import io.openems.edge.common.modbusslave.ModbusSlaveTable;
+import io.openems.edge.common.taskmanager.Priority;
+import io.openems.edge.meter.api.ElectricityMeter;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.component.ComponentContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.osgi.service.component.annotations.ReferencePolicyOption;
+import org.osgi.service.component.annotations.ConfigurationPolicy;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferencePolicy;
+import org.osgi.service.metatype.annotations.Designate;
+
+@Designate(ocd = Config.class, factory = true)
+@Component(//
+ name = "Meter.inepro.Pro380ModCT", //
+ immediate = true, //
+ configurationPolicy = ConfigurationPolicy.REQUIRE //
+)
+
+
+public class Pro380modctImpl extends AbstractOpenemsModbusComponent
+ implements Pro380modct, ElectricityMeter, ModbusComponent, OpenemsComponent {
+
+ @Reference
+ private ConfigurationAdmin cm;
+
+ @Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY)
+ protected void setModbus(BridgeModbus modbus) {
+ super.setModbus(modbus);
+ }
+
+ private Config config = null;
+ private boolean invert;
+
+ public Pro380modctImpl() {
+ super(//
+ OpenemsComponent.ChannelId.values(), //
+ ModbusComponent.ChannelId.values(), //
+ ElectricityMeter.ChannelId.values(), //
+ Pro380modct.ChannelId.values() //
+ );
+ ElectricityMeter.calculateSumCurrentFromPhases(this);
+ ElectricityMeter.calculateAverageVoltageFromPhases(this);
+ }
+
+ @Activate
+ private void activate(ComponentContext context, Config config) throws OpenemsException {
+ this.config = config;
+ this.invert = config.invert();
+ if (super.activate(context, config.id(), config.alias(), config.enabled(), config.modbusUnitId(), this.cm,
+ "Modbus", config.modbus_id())) {
+ return;
+ }
+ }
+
+ @Override
+ public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) {
+ return new ModbusSlaveTable(//
+ OpenemsComponent.getModbusSlaveNatureTable(accessMode), //
+ ElectricityMeter.getModbusSlaveNatureTable(accessMode), //
+ ModbusSlaveNatureTable.of(Pro380modct.class, accessMode, 100) //
+ .build());
+ }
+
+ @Override
+ @Deactivate
+ protected void deactivate() {
+ super.deactivate();
+ }
+
+ @Override
+ protected ModbusProtocol defineModbusProtocol() {
+ var modbusProtocol = new ModbusProtocol(this, //
+ new FC3ReadRegistersTask(0x5002, Priority.HIGH, //
+ m(ElectricityMeter.ChannelId.VOLTAGE_L1, //
+ new FloatDoublewordElement(0x5002).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ m(ElectricityMeter.ChannelId.VOLTAGE_L2, //
+ new FloatDoublewordElement(0x5004).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ m(ElectricityMeter.ChannelId.VOLTAGE_L3, //
+ new FloatDoublewordElement(0x5006).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ m(ElectricityMeter.ChannelId.FREQUENCY, //
+ new FloatDoublewordElement(0x5008).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ new DummyRegisterElement(0x500A, 0x500B), // Current* (PRO1 only)
+ m(ElectricityMeter.ChannelId.CURRENT_L1, //
+ new FloatDoublewordElement(0x500C).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)), //
+ m(ElectricityMeter.ChannelId.CURRENT_L2, //
+ new FloatDoublewordElement(0x500E).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)), //
+ m(ElectricityMeter.ChannelId.CURRENT_L3, //
+ new FloatDoublewordElement(0x5010).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)), //
+ m(ElectricityMeter.ChannelId.ACTIVE_POWER, //
+ new FloatDoublewordElement(0x5012).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)), //
+ m(ElectricityMeter.ChannelId.ACTIVE_POWER_L1, //
+ new FloatDoublewordElement(0x5014).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)), //
+ m(ElectricityMeter.ChannelId.ACTIVE_POWER_L2, //
+ new FloatDoublewordElement(0x5016).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)), //
+ m(ElectricityMeter.ChannelId.ACTIVE_POWER_L3, //
+ new FloatDoublewordElement(0x5018).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)), //
+ m(ElectricityMeter.ChannelId.REACTIVE_POWER, //
+ new FloatDoublewordElement(0x501A).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)), //
+ m(ElectricityMeter.ChannelId.REACTIVE_POWER_L1, //
+ new FloatDoublewordElement(0x501C).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)), //
+ m(ElectricityMeter.ChannelId.REACTIVE_POWER_L2, //
+ new FloatDoublewordElement(0x501E).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)), //
+ m(ElectricityMeter.ChannelId.REACTIVE_POWER_L3, //
+ new FloatDoublewordElement(0x5020).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)), //
+ m(Pro380modct.ChannelId.APPARENT_POWER, //
+ new FloatDoublewordElement(0x5022).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)), //
+ m(Pro380modct.ChannelId.APPARENT_POWER_L1, //
+ new FloatDoublewordElement(0x5024).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)), //
+ m(Pro380modct.ChannelId.APPARENT_POWER_L2, //
+ new FloatDoublewordElement(0x5026).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)), //
+ m(Pro380modct.ChannelId.APPARENT_POWER_L3, //
+ new FloatDoublewordElement(0x5028).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)) //
+ ) //
+ );
+
+ if (this.invert) {
+ modbusProtocol.addTask(new FC3ReadRegistersTask(0x600C, Priority.LOW, //
+ m(ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY, //
+ new FloatDoublewordElement(0x600C).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ new DummyRegisterElement(0x600E, 0x6011), //
+ m(ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY_L1, //
+ new FloatDoublewordElement(0x6012).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ m(ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY_L2, //
+ new FloatDoublewordElement(0x6014).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ m(ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY_L3, //
+ new FloatDoublewordElement(0x6016).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ m(ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY, //
+ new FloatDoublewordElement(0x6018).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ new DummyRegisterElement(0x601A, 0x601D), //
+ m(ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY_L1, //
+ new FloatDoublewordElement(0x601E).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ m(ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY_L2, //
+ new FloatDoublewordElement(0x6020).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ m(ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY_L3, //
+ new FloatDoublewordElement(0x6022).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3) //
+ ));
+ } else { // not invert
+ modbusProtocol.addTask(new FC3ReadRegistersTask(0x600C, Priority.LOW, //
+ m(ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY, //
+ new FloatDoublewordElement(0x600C).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ new DummyRegisterElement(0x600E, 0x6011), //
+ m(ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY_L1, //
+ new FloatDoublewordElement(0x6012).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ m(ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY_L2, //
+ new FloatDoublewordElement(0x6014).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ m(ElectricityMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY_L3, //
+ new FloatDoublewordElement(0x6016).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ m(ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY, //
+ new FloatDoublewordElement(0x6018).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ new DummyRegisterElement(0x601A, 0x601D), //
+ m(ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY_L1, //
+ new FloatDoublewordElement(0x601E).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ m(ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY_L2, //
+ new FloatDoublewordElement(0x6020).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3), //
+ m(ElectricityMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY_L3, //
+ new FloatDoublewordElement(0x6022).wordOrder(WordOrder.MSWLSW), //
+ SCALE_FACTOR_3) //
+ ));
+ }
+
+ return modbusProtocol;
+ }
+
+ @Override
+ public String debugLog() {
+ return "L:" + this.getActivePower().asString();
+ }
+
+ @Override
+ public MeterType getMeterType() {
+ return this.config.type();
+ }
+}
\ No newline at end of file
diff --git a/io.openems.edge.meter.inepro/test/.gitignore b/io.openems.edge.meter.inepro/test/.gitignore
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/io.openems.edge.meter.inepro/test/io/openems/edge/meter/inepro/pro380modct/MyConfig.java b/io.openems.edge.meter.inepro/test/io/openems/edge/meter/inepro/pro380modct/MyConfig.java
new file mode 100755
index 00000000000..0b9047ace9a
--- /dev/null
+++ b/io.openems.edge.meter.inepro/test/io/openems/edge/meter/inepro/pro380modct/MyConfig.java
@@ -0,0 +1,90 @@
+package io.openems.edge.meter.inepro.pro380modct;
+
+import io.openems.common.utils.ConfigUtils;
+import io.openems.common.test.AbstractComponentConfig;
+import io.openems.common.types.MeterType;
+
+@SuppressWarnings("all")
+public class MyConfig extends AbstractComponentConfig implements Config {
+
+ public static class Builder {
+ private String id;
+ private String modbusId = null;
+ private int modbusUnitId;
+ private MeterType type;
+ private boolean invert;
+
+ private Builder() {
+ }
+
+ public Builder setId(String id) {
+ this.id = id;
+ return this;
+ }
+
+ public Builder setModbusId(String modbusId) {
+ this.modbusId = modbusId;
+ return this;
+ }
+
+ public Builder setType(MeterType type) {
+ this.type = type;
+ return this;
+ }
+
+ public Builder setModbusUnitId(int modbusUnitId) {
+ this.modbusUnitId = modbusUnitId;
+ return this;
+ }
+
+ public Builder setInvert(boolean invert) {
+ this.invert = invert;
+ return this;
+ }
+
+ public MyConfig build() {
+ return new MyConfig(this);
+ }
+ }
+
+ /**
+ * Create a Config builder.
+ *
+ * @return a {@link Builder}
+ */
+ public static Builder create() {
+ return new Builder();
+ }
+
+ private final Builder builder;
+
+ private MyConfig(Builder builder) {
+ super(Config.class, builder.id);
+ this.builder = builder;
+ }
+
+ @Override
+ public String modbus_id() {
+ return this.builder.modbusId;
+ }
+
+ @Override
+ public String Modbus_target() {
+ return ConfigUtils.generateReferenceTargetFilter(this.id(), this.modbus_id());
+ }
+
+ @Override
+ public int modbusUnitId() {
+ return this.builder.modbusUnitId;
+ }
+
+ @Override
+ public MeterType type() {
+ return this.builder.type;
+ }
+
+ @Override
+ public boolean invert() {
+ return this.builder.invert;
+ }
+}
diff --git a/io.openems.edge.meter.inepro/test/io/openems/edge/meter/inepro/pro380modct/Pro380modctImplTest.java b/io.openems.edge.meter.inepro/test/io/openems/edge/meter/inepro/pro380modct/Pro380modctImplTest.java
new file mode 100644
index 00000000000..d72419f24f0
--- /dev/null
+++ b/io.openems.edge.meter.inepro/test/io/openems/edge/meter/inepro/pro380modct/Pro380modctImplTest.java
@@ -0,0 +1,170 @@
+package io.openems.edge.meter.inepro.pro380modct;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import io.openems.common.test.DummyConfigurationAdmin;
+import io.openems.common.types.MeterType;
+import io.openems.edge.bridge.modbus.test.DummyModbusBridge;
+import io.openems.edge.common.test.AbstractComponentTest.TestCase;
+import io.openems.edge.common.test.ComponentTest;
+import io.openems.edge.meter.api.ElectricityMeter;
+import io.openems.edge.meter.test.InvertTest;
+
+public class Pro380modctImplTest {
+
+ private ComponentTest test;
+
+ @Before
+ public void setup() throws Exception {
+ this.test = new ComponentTest(new Pro380modctImpl()) //
+ .addReference("cm", new DummyConfigurationAdmin()) //
+ .addReference("setModbus", new DummyModbusBridge("modbus0") //
+ .withRegisters(0x5002,
+ // VOLTAGE_L1 230.0 V -> 230000 mV
+ 0x4366, 0x0000,
+ // VOLTAGE_L2 231.0 V -> 231000 mV
+ 0x4367, 0x0000,
+ // VOLTAGE_L3 232.0 V -> 232000 mV
+ 0x4368, 0x0000,
+ // FREQUENCY 50.1 Hz -> 50100 mHz
+ 0x4248, 0x6666,
+ // Dummy (Current* PRO1 only)
+ 0x0000, 0x0000,
+ // CURRENT_L1 11.5 A -> 11500 mA
+ 0x4138, 0x0000,
+ // CURRENT_L2 12.5 A -> 12500 mA
+ 0x4148, 0x0000,
+ // CURRENT_L3 11.1 A -> 11100 mA
+ 0x4131, 0x999a,
+ // ACTIVE_POWER 1.5 kW -> 1500 W
+ 0x3fc0, 0x0000,
+ // ACTIVE_POWER_L1 1.6 kW -> 1600 W
+ 0x3fcc, 0xcccd,
+ // ACTIVE_POWER_L2 1.7 kW -> 1700 W
+ 0x3fd9, 0x999a,
+ // ACTIVE_POWER_L3 2.5 kW -> 2500 W
+ 0x4020, 0x0000,
+ // REACTIVE_POWER 2.6 kvar -> 2600 var
+ 0x4026, 0x6666,
+ // REACTIVE_POWER_L1 2.7 kvar -> 2700 var
+ 0x402c, 0xcccd,
+ // REACTIVE_POWER_L2 1.5 kvar -> 1500 var
+ 0x3fc0, 0x0000,
+ // REACTIVE_POWER_L3 1.7 kvar -> 1700 var
+ 0x3fd9, 0x999a,
+ // APPARENT_POWER 12.2 kVA -> 12200 VA
+ 0x4143, 0x3333,
+ // APPARENT_POWER_L1 13.3 kVA -> 13300 VA
+ 0x4154, 0xcccd,
+ // APPARENT_POWER_L2 12.5 kVA -> 12500 VA
+ 0x4148, 0x0000,
+ // APPARENT_POWER_L3 11.5 kVA -> 11500 VA
+ 0x4138, 0x0000) //
+ .withRegisters(0x600C,
+ // Forward Active Energy = 0.0 kWh -> 0 Wh
+ // (-> CONSUMPTION when !invert, PRODUCTION when invert)
+ 0x0000, 0x0000,
+ // T1 Forward Active Energy (dummy)
+ 0x0000, 0x0000,
+ // T2 Forward Active Energy (dummy)
+ 0x0000, 0x0000,
+ // L1 Forward Active Energy
+ 0x0000, 0x0000,
+ // L2 Forward Active Energy
+ 0x0000, 0x0000,
+ // L3 Forward Active Energy
+ 0x0000, 0x0000,
+ // Reverse Active Energy = 13.0 kWh -> 13000 Wh
+ // (-> PRODUCTION when !invert, CONSUMPTION when invert)
+ 0x4150, 0x0001,
+ // T1 Reverse Active Energy (dummy)
+ 0x0000, 0x0000,
+ // T2 Reverse Active Energy (dummy)
+ 0x0000, 0x0000,
+ // L1 Reverse Active Energy
+ 0x0000, 0x0000,
+ // L2 Reverse Active Energy
+ 0x0000, 0x0000,
+ // L3 Reverse Active Energy
+ 0x0000, 0x0000)); //
+ }
+
+ @Test
+ public void testMapping() throws Exception {
+ this.test.activate(MyConfig.create() //
+ .setId("meter0") //
+ .setModbusId("modbus0") //
+ .setModbusUnitId(1) //
+ .setType(MeterType.GRID) //
+ .setInvert(false) //
+ .build()) //
+ .next(new TestCase() //
+ .output(ElectricityMeter.ChannelId.VOLTAGE_L1, 230000) //
+ .output(ElectricityMeter.ChannelId.VOLTAGE_L2, 231000) //
+ .output(ElectricityMeter.ChannelId.VOLTAGE_L3, 232000) //
+ .output(ElectricityMeter.ChannelId.VOLTAGE, 231000) // (230000+231000+232000)/3
+ .output(ElectricityMeter.ChannelId.FREQUENCY, 50100) //
+ .output(ElectricityMeter.ChannelId.CURRENT_L1, 11500) //
+ .output(ElectricityMeter.ChannelId.CURRENT_L2, 12500) //
+ .output(ElectricityMeter.ChannelId.CURRENT_L3, 11100) //
+ .output(ElectricityMeter.ChannelId.CURRENT, 35100) // 11500+12500+11100
+ .output(ElectricityMeter.ChannelId.ACTIVE_POWER, 1500) //
+ .output(ElectricityMeter.ChannelId.ACTIVE_POWER_L1, 1600) //
+ .output(ElectricityMeter.ChannelId.ACTIVE_POWER_L2, 1700) //
+ .output(ElectricityMeter.ChannelId.ACTIVE_POWER_L3, 2500) //
+ .output(ElectricityMeter.ChannelId.REACTIVE_POWER, 2600) //
+ .output(ElectricityMeter.ChannelId.REACTIVE_POWER_L1, 2700) //
+ .output(ElectricityMeter.ChannelId.REACTIVE_POWER_L2, 1500) //
+ .output(ElectricityMeter.ChannelId.REACTIVE_POWER_L3, 1700) //
+ .output(Pro380modct.ChannelId.APPARENT_POWER, 12200) //
+ .output(Pro380modct.ChannelId.APPARENT_POWER_L1, 13300) //
+ .output(Pro380modct.ChannelId.APPARENT_POWER_L2, 12500) //
+ .output(Pro380modct.ChannelId.APPARENT_POWER_L3, 11500)); //
+ }
+
+ @Test
+ public void testEnergyNoInvert() throws Exception {
+ this.test.activate(MyConfig.create() //
+ .setId("meter0") //
+ .setModbusId("modbus0") //
+ .setModbusUnitId(1) //
+ .setType(MeterType.GRID) //
+ .setInvert(false) //
+ .build()) //
+ .next(new TestCase()) //
+ .next(InvertTest.testEnergyInvert(false)); //
+ }
+
+ @Test
+ public void testEnergyWithInvert() throws Exception {
+ this.test.activate(MyConfig.create() //
+ .setId("meter0") //
+ .setModbusId("modbus0") //
+ .setModbusUnitId(1) //
+ .setType(MeterType.GRID) //
+ .setInvert(true) //
+ .build()) //
+ .next(new TestCase()) //
+ .next(InvertTest.testEnergyInvert(true)); //
+ }
+
+ @Test
+ public void testMeterType() throws Exception {
+ var component = new Pro380modctImpl();
+ new ComponentTest(component) //
+ .addReference("cm", new DummyConfigurationAdmin()) //
+ .addReference("setModbus", new DummyModbusBridge("modbus0")) //
+ .activate(MyConfig.create() //
+ .setId("meter0") //
+ .setModbusId("modbus0") //
+ .setModbusUnitId(1) //
+ .setType(MeterType.PRODUCTION) //
+ .setInvert(false) //
+ .build());
+
+ assertEquals(MeterType.PRODUCTION, component.getMeterType());
+ }
+}