Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions io.openems.edge.application/EdgeApp.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -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',\
Expand Down Expand Up @@ -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,\
Expand Down
12 changes: 12 additions & 0 deletions io.openems.edge.meter.inepro/.classpath
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>
2 changes: 2 additions & 0 deletions io.openems.edge.meter.inepro/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/bin_test/
/generated/
23 changes: 23 additions & 0 deletions io.openems.edge.meter.inepro/.project
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
16 changes: 16 additions & 0 deletions io.openems.edge.meter.inepro/bnd.bnd
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
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -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 {
Copy link
Collaborator

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


@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}]";
}
Original file line number Diff line number Diff line change
@@ -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;
}
}

}
Original file line number Diff line number Diff line change
@@ -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;
Copy link
Collaborator

Choose a reason for hiding this comment

The 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.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 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ModbusSlave is missing - It would still be inherited from the Interface, but Best Practice would list it here


@Reference
private ConfigurationAdmin cm;

@Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY)
protected void setModbus(BridgeModbus modbus) {
Copy link
Collaborator

Choose a reason for hiding this comment

The 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;
private boolean invert;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creates a second source of truth. KDK accesses this.config.invert() directly. Since this.config is assigned before super.activate() calls defineModbusProtocol(), direct access is safe.


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();
}
}
Empty file.
Loading