-
Notifications
You must be signed in to change notification settings - Fork 563
[Edge] Implement Inepro Pro380ModCT meter #3570
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 2 commits
af7e458
f6f7639
ae8f110
72b6b3f
3ac05be
d3a5ddb
00b0669
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <classpath> | ||
| <classpathentry kind="con" path="aQute.bnd.classpath.container"/> | ||
| <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21"/> | ||
| <classpathentry kind="src" output="bin" path="src"/> | ||
| <classpathentry kind="src" output="bin_test" path="test"> | ||
| <attributes> | ||
| <attribute name="test" value="true"/> | ||
| </attributes> | ||
| </classpathentry> | ||
| <classpathentry kind="output" path="bin"/> | ||
| </classpath> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| /bin_test/ | ||
| /generated/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <projectDescription> | ||
| <name>io.openems.edge.meter.inepro</name> | ||
| <comment></comment> | ||
| <projects> | ||
| </projects> | ||
| <buildSpec> | ||
| <buildCommand> | ||
| <name>org.eclipse.jdt.core.javabuilder</name> | ||
| <arguments> | ||
| </arguments> | ||
| </buildCommand> | ||
| <buildCommand> | ||
| <name>bndtools.core.bndbuilder</name> | ||
| <arguments> | ||
| </arguments> | ||
| </buildCommand> | ||
| </buildSpec> | ||
| <natures> | ||
| <nature>org.eclipse.jdt.core.javanature</nature> | ||
| <nature>bndtools.core.bndnature</nature> | ||
| </natures> | ||
| </projectDescription> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| eclipse.preferences.version=1 | ||
| encoding/<project>=UTF-8 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| 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"; | ||
|
|
||
tomflorentin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| @AttributeDefinition(name = "Modbus Unit-ID", description = "The Unit-ID of the Modbus device.") | ||
| int modbusUnitId() default 1; | ||
|
|
||
| @AttributeDefinition(name = "Modbus target filter", description = "This is auto-generated by 'Modbus-ID'.") | ||
| String Modbus_target() default "(enabled=true)"; | ||
|
|
||
| String webconsole_configurationFactory_nameHint() default "io.openems.edge.meter.pro380modct [{id}]"; | ||
tomflorentin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| @AttributeDefinition(name = "Meter-Type", description = "What is measured by this Meter?") | ||
|
||
| MeterType type() default MeterType.CONSUMPTION_METERED; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| 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.meter.api.ElectricityMeter; | ||
|
|
||
| public interface Pro380modct extends ElectricityMeter, OpenemsComponent { | ||
|
|
||
| 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; | ||
| } | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,162 @@ | ||
| package io.openems.edge.meter.inepro.pro380modct; | ||
|
|
||
| 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; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also please apply Ctrl+Shift+O after all for Sorting the imports |
||
| import io.openems.edge.bridge.modbus.api.ElementToChannelConverter; | ||
| import io.openems.edge.bridge.modbus.api.ModbusComponent; | ||
| import io.openems.edge.bridge.modbus.api.ModbusProtocol; | ||
| 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.edge.common.component.OpenemsComponent; | ||
| 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) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Method overrides AbstractOpenemsModbusComponent.setModbus(). The @OverRide annotation provides compile-time safety and documents intent. |
||
| super.setModbus(modbus); | ||
| } | ||
|
|
||
| private Config config = null; | ||
|
|
||
| public Pro380modctImpl() { | ||
| super(// | ||
| OpenemsComponent.ChannelId.values(), // | ||
| ModbusComponent.ChannelId.values(), // | ||
| ElectricityMeter.ChannelId.values(), // | ||
| Pro380modct.ChannelId.values() // | ||
| ); | ||
| } | ||
|
|
||
| @Activate | ||
| private void activate(ComponentContext context, Config config) throws OpenemsException { | ||
| if (super.activate(context, config.id(), config.alias(), config.enabled(), config.modbusUnitId(), this.cm, "Modbus", | ||
| config.modbus_id())) { | ||
| return; | ||
| } | ||
| this.config = config; | ||
| } | ||
|
|
||
| @Override | ||
| @Deactivate | ||
| protected void deactivate() { | ||
| super.deactivate(); | ||
| } | ||
|
|
||
| @Override | ||
| protected ModbusProtocol defineModbusProtocol() { | ||
tomflorentin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| var modbusProtocol = new ModbusProtocol(this, // | ||
| // VOLTAGE + FREQUENCY | ||
| new FC3ReadRegistersTask(0x5002, Priority.HIGH, // | ||
| m(ElectricityMeter.ChannelId.VOLTAGE_L1, // | ||
| new FloatDoublewordElement(0x5002).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3), // | ||
| m(ElectricityMeter.ChannelId.VOLTAGE_L2, // | ||
| new FloatDoublewordElement(0x5004).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3), // | ||
| m(ElectricityMeter.ChannelId.VOLTAGE_L3, // | ||
| new FloatDoublewordElement(0x5006).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3), // | ||
| m(ElectricityMeter.ChannelId.FREQUENCY, // | ||
| new FloatDoublewordElement(0x5008).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3) // | ||
| ), // | ||
| // CURRENT (total + L1/L2/L3) | ||
| new FC3ReadRegistersTask(0x500A, Priority.HIGH, // | ||
| m(ElectricityMeter.ChannelId.CURRENT, // | ||
| new FloatDoublewordElement(0x500A).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3), // | ||
| m(ElectricityMeter.ChannelId.CURRENT_L1, // | ||
| new FloatDoublewordElement(0x500C).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3), // | ||
| m(ElectricityMeter.ChannelId.CURRENT_L2, // | ||
| new FloatDoublewordElement(0x500E).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3), // | ||
| m(ElectricityMeter.ChannelId.CURRENT_L3, // | ||
| new FloatDoublewordElement(0x5010).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3) // | ||
| ), // | ||
| // ACTIVE POWER (kW) total + L1/L2/L3 | ||
| new FC3ReadRegistersTask(0x5012, Priority.HIGH, // | ||
| m(ElectricityMeter.ChannelId.ACTIVE_POWER, // | ||
| new FloatDoublewordElement(0x5012).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3), // | ||
| m(ElectricityMeter.ChannelId.ACTIVE_POWER_L1, // | ||
| new FloatDoublewordElement(0x5014).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3), // | ||
| m(ElectricityMeter.ChannelId.ACTIVE_POWER_L2, // | ||
| new FloatDoublewordElement(0x5016).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3), // | ||
| m(ElectricityMeter.ChannelId.ACTIVE_POWER_L3, // | ||
| new FloatDoublewordElement(0x5018).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3) // | ||
| ), // | ||
| // REACTIVE POWER (kvar) total + L1/L2/L3 | ||
| new FC3ReadRegistersTask(0x501A, Priority.HIGH, // | ||
| m(ElectricityMeter.ChannelId.REACTIVE_POWER, // | ||
| new FloatDoublewordElement(0x501A).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3), // | ||
| m(ElectricityMeter.ChannelId.REACTIVE_POWER_L1, // | ||
| new FloatDoublewordElement(0x501C).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3), // | ||
| m(ElectricityMeter.ChannelId.REACTIVE_POWER_L2, // | ||
| new FloatDoublewordElement(0x501E).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3), // | ||
| m(ElectricityMeter.ChannelId.REACTIVE_POWER_L3, // | ||
| new FloatDoublewordElement(0x5020).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3) // | ||
| ), // | ||
| // APPARENT POWER (kVA) total + L1/L2/L3 | ||
| new FC3ReadRegistersTask(0x5022, Priority.HIGH, // | ||
| m(Pro380modct.ChannelId.APPARENT_POWER, // | ||
| new FloatDoublewordElement(0x5022).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3), // | ||
| m(Pro380modct.ChannelId.APPARENT_POWER_L1, // | ||
| new FloatDoublewordElement(0x5024).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3), // | ||
| m(Pro380modct.ChannelId.APPARENT_POWER_L2, // | ||
| new FloatDoublewordElement(0x5026).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3), // | ||
| m(Pro380modct.ChannelId.APPARENT_POWER_L3, // | ||
| new FloatDoublewordElement(0x5028).wordOrder(WordOrder.MSWLSW), // | ||
| ElementToChannelConverter.SCALE_FACTOR_3) // | ||
| ) // | ||
| ); | ||
|
|
||
| return modbusProtocol; | ||
| } | ||
|
|
||
tomflorentin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| @Override | ||
| public String debugLog() { | ||
tomflorentin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return "L:" + this.getActivePower().asString(); | ||
| } | ||
|
|
||
tomflorentin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| @Override | ||
| public MeterType getMeterType() { | ||
| return this.config.type(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| 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 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 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; | ||
| } | ||
|
|
||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Config should be package-private - it's an internal implementation detail, not part of the public api