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()); + } +}