Skip to content
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

initial commit for Siemens PAC 3200 meter #1667

Merged
merged 9 commits into from Dec 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion io.openems.edge.application/EdgeApp.bndrun
Expand Up @@ -127,6 +127,7 @@
bnd.identity;id='io.openems.edge.meter.microcare.sdm630',\
bnd.identity;id='io.openems.edge.meter.pqplus',\
bnd.identity;id='io.openems.edge.meter.schneider.acti9.smartlink',\
bnd.identity;id='io.openems.edge.meter.siemens',\
bnd.identity;id='io.openems.edge.meter.sma.shm20',\
bnd.identity;id='io.openems.edge.meter.socomec',\
bnd.identity;id='io.openems.edge.meter.sunspec',\
Expand Down Expand Up @@ -268,6 +269,7 @@
io.openems.edge.meter.microcare.sdm630;version=snapshot,\
io.openems.edge.meter.pqplus;version=snapshot,\
io.openems.edge.meter.schneider.acti9.smartlink;version=snapshot,\
io.openems.edge.meter.siemens;version=snapshot,\
io.openems.edge.meter.sma.shm20;version=snapshot,\
io.openems.edge.meter.socomec;version=snapshot,\
io.openems.edge.meter.sunspec;version=snapshot,\
Expand Down Expand Up @@ -327,4 +329,4 @@
org.ops4j.pax.logging.pax-logging-log4j1;version='[2.0.10,2.0.11)',\
org.osgi.util.function;version='[1.2.0,1.2.1)',\
org.osgi.util.promise;version='[1.2.0,1.2.1)',\
rrd4j;version='[3.8.0,3.8.1)'
rrd4j;version='[3.8.0,3.8.1)'
@@ -0,0 +1,30 @@
package io.openems.edge.bridge.modbus.api.element;

import io.openems.common.types.OpenemsType;

import java.nio.ByteBuffer;

/**
* A FloatQuadruplewordElement represents a Float value in an
* {@link AbstractQuadrupleWordElement}.
*/
public class FloatQuadruplewordElement extends AbstractQuadrupleWordElement<FloatQuadruplewordElement, Double> {

public FloatQuadruplewordElement(int address) {
super(OpenemsType.DOUBLE, address);
}

@Override
protected FloatQuadruplewordElement self() {
return this;
}

protected Double fromByteBuffer(ByteBuffer buff) {
return Double.valueOf(buff.getDouble());
}

protected ByteBuffer toByteBuffer(ByteBuffer buff, Double value) {
return buff.putDouble(value.doubleValue());
}

}
12 changes: 12 additions & 0 deletions io.openems.edge.meter.siemens/.classpath
@@ -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-11"/>
<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.siemens/.gitignore
@@ -0,0 +1,2 @@
/bin_test/
/generated/
23 changes: 23 additions & 0 deletions io.openems.edge.meter.siemens/.project
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>io.openems.edge.meter.siemens</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>
15 changes: 15 additions & 0 deletions io.openems.edge.meter.siemens/bnd.bnd
@@ -0,0 +1,15 @@
Bundle-Name: OpenEMS Edge Meter Siemens
Bundle-Description: This implementation covers Siemens PAC2200/3200/4200
Bundle-Vendor: Ernst KNOLL Feinmechanik GmbH
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,\

-testpath: \
${testpath}
8 changes: 8 additions & 0 deletions io.openems.edge.meter.siemens/readme.adoc
@@ -0,0 +1,8 @@
= Siemens Meters PAC2200 / 3200 / 4200

Implemented Natures

- SymmetricMeter
- AsymmetricMeter

https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.meter.siemens[Source Code icon:github[]]
@@ -0,0 +1,38 @@
package io.openems.edge.meter.siemens;

import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;

import io.openems.edge.meter.api.MeterType;

@ObjectClassDefinition(//
name = "Siemens PAC 2200/3200/4200", //
description = "Implements the Siemens PAC 2200/3200/4200 power analyser.")
@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 = "Meter-Type", description = "What is measured by this Meter?")
MeterType type() default MeterType.PRODUCTION;

@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. Defaults to '1' for Modbus/TCP.")
int modbusUnitId() default 1;

@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 "Siemens PAC 2200/3200/4200 [{id}]";
}
@@ -0,0 +1,25 @@
package io.openems.edge.meter.siemens;

import io.openems.edge.bridge.modbus.api.ModbusComponent;
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.AsymmetricMeter;
import io.openems.edge.meter.api.SymmetricMeter;

public interface SiemensPacMeter
extends SymmetricMeter, AsymmetricMeter, ModbusComponent, OpenemsComponent, ModbusSlave {

public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
;
private final Doc doc;

private ChannelId(Doc doc) {
this.doc = doc;
}

public Doc doc() {
return this.doc;
}
}
}
@@ -0,0 +1,162 @@
package io.openems.edge.meter.siemens;

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.ConfigurationPolicy;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.osgi.service.component.annotations.ReferencePolicyOption;
import org.osgi.service.metatype.annotations.Designate;

import io.openems.common.channel.AccessMode;
import io.openems.common.exceptions.OpenemsException;
import io.openems.edge.bridge.modbus.api.AbstractOpenemsModbusComponent;
import io.openems.edge.bridge.modbus.api.BridgeModbus;
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.DummyRegisterElement;
import io.openems.edge.bridge.modbus.api.element.FloatDoublewordElement;
import io.openems.edge.bridge.modbus.api.element.FloatQuadruplewordElement;
import io.openems.edge.bridge.modbus.api.task.FC3ReadRegistersTask;
import io.openems.edge.common.component.OpenemsComponent;
import io.openems.edge.common.modbusslave.ModbusSlave;
import io.openems.edge.common.modbusslave.ModbusSlaveTable;
import io.openems.edge.common.taskmanager.Priority;
import io.openems.edge.meter.api.AsymmetricMeter;
import io.openems.edge.meter.api.MeterType;
import io.openems.edge.meter.api.SymmetricMeter;

/**
* Implements the Siemens PAC2200/3200/4200 power meter.
*
* <p>
* https://cache.industry.siemens.com/dl/files/150/26504150/att_906558/v1/A5E01168664B-04_EN-US_122016_201612221316360495.pdf
*/
@Designate(ocd = Config.class, factory = true)
@Component(//
name = "Meter.Siemens", //
immediate = true, //
configurationPolicy = ConfigurationPolicy.REQUIRE //
)
public class SiemensPacMeterImpl extends AbstractOpenemsModbusComponent
implements SiemensPacMeter, SymmetricMeter, AsymmetricMeter, ModbusComponent, OpenemsComponent, ModbusSlave {

private MeterType meterType = MeterType.PRODUCTION;

/*
* Invert power values
*/
private boolean invert = false;

@Reference
protected ConfigurationAdmin cm;

public SiemensPacMeterImpl() {
super(//
OpenemsComponent.ChannelId.values(), //
ModbusComponent.ChannelId.values(), //
SymmetricMeter.ChannelId.values(), //
AsymmetricMeter.ChannelId.values(), //
SiemensPacMeter.ChannelId.values() //
);
}

@Reference(policy = ReferencePolicy.STATIC, policyOption = ReferencePolicyOption.GREEDY, cardinality = ReferenceCardinality.MANDATORY)
protected void setModbus(BridgeModbus modbus) {
super.setModbus(modbus);
}

@Activate
void activate(ComponentContext context, Config config) throws OpenemsException {
this.meterType = config.type();
this.invert = config.invert();

if (super.activate(context, config.id(), config.alias(), config.enabled(), config.modbusUnitId(), this.cm,
"Modbus", config.modbus_id())) {
return;
}
}

@Deactivate
protected void deactivate() {
super.deactivate();
}

@Override
public MeterType getMeterType() {
return this.meterType;
}

@Override
protected ModbusProtocol defineModbusProtocol() throws OpenemsException {

ModbusProtocol modbusProtocol = new ModbusProtocol(this, //
new FC3ReadRegistersTask(1, Priority.HIGH, //
m(AsymmetricMeter.ChannelId.VOLTAGE_L1, new FloatDoublewordElement(1),
ElementToChannelConverter.SCALE_FACTOR_3),
m(AsymmetricMeter.ChannelId.VOLTAGE_L2, new FloatDoublewordElement(3),
ElementToChannelConverter.SCALE_FACTOR_3),
m(AsymmetricMeter.ChannelId.VOLTAGE_L3, new FloatDoublewordElement(5),
ElementToChannelConverter.SCALE_FACTOR_3),
new DummyRegisterElement(7, 12), //
m(AsymmetricMeter.ChannelId.CURRENT_L1, new FloatDoublewordElement(13),
ElementToChannelConverter.SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)),
m(AsymmetricMeter.ChannelId.CURRENT_L2, new FloatDoublewordElement(15),
ElementToChannelConverter.SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)),
m(AsymmetricMeter.ChannelId.CURRENT_L3, new FloatDoublewordElement(17),
ElementToChannelConverter.SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)),
new DummyRegisterElement(19, 24), //
m(AsymmetricMeter.ChannelId.ACTIVE_POWER_L1, new FloatDoublewordElement(25),
ElementToChannelConverter.INVERT_IF_TRUE(this.invert)),
m(AsymmetricMeter.ChannelId.ACTIVE_POWER_L2, new FloatDoublewordElement(27),
ElementToChannelConverter.INVERT_IF_TRUE(this.invert)),
m(AsymmetricMeter.ChannelId.ACTIVE_POWER_L3, new FloatDoublewordElement(29),
ElementToChannelConverter.INVERT_IF_TRUE(this.invert)),
m(AsymmetricMeter.ChannelId.REACTIVE_POWER_L1, new FloatDoublewordElement(31),
ElementToChannelConverter.INVERT_IF_TRUE(this.invert)),
m(AsymmetricMeter.ChannelId.REACTIVE_POWER_L2, new FloatDoublewordElement(33),
ElementToChannelConverter.INVERT_IF_TRUE(this.invert)),
m(AsymmetricMeter.ChannelId.REACTIVE_POWER_L3, new FloatDoublewordElement(35),
ElementToChannelConverter.INVERT_IF_TRUE(this.invert)),
new DummyRegisterElement(37, 60), //
m(SymmetricMeter.ChannelId.CURRENT, new FloatDoublewordElement(61),
ElementToChannelConverter.SCALE_FACTOR_3_AND_INVERT_IF_TRUE(this.invert)),
new DummyRegisterElement(63, 64), //
m(SymmetricMeter.ChannelId.ACTIVE_POWER, new FloatDoublewordElement(65),
ElementToChannelConverter.INVERT_IF_TRUE(this.invert)),
m(SymmetricMeter.ChannelId.REACTIVE_POWER, new FloatDoublewordElement(67),
ElementToChannelConverter.INVERT_IF_TRUE(this.invert))));
if (this.invert) {
modbusProtocol.addTask(new FC3ReadRegistersTask(801, Priority.LOW, //
m(SymmetricMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY, new FloatQuadruplewordElement(801)),
new DummyRegisterElement(805, 808), //
m(SymmetricMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY, new FloatQuadruplewordElement(809))));
} else {
modbusProtocol.addTask(new FC3ReadRegistersTask(801, Priority.LOW, //
m(SymmetricMeter.ChannelId.ACTIVE_PRODUCTION_ENERGY, new FloatQuadruplewordElement(801)),
new DummyRegisterElement(805, 808), //
m(SymmetricMeter.ChannelId.ACTIVE_CONSUMPTION_ENERGY, new FloatQuadruplewordElement(809))));
}

return modbusProtocol;
}

@Override
public String debugLog() {
return "L:" + this.getActivePower().asString();
}

@Override
public ModbusSlaveTable getModbusSlaveTable(AccessMode accessMode) {
return new ModbusSlaveTable(//
OpenemsComponent.getModbusSlaveNatureTable(accessMode), //
SymmetricMeter.getModbusSlaveNatureTable(accessMode), //
AsymmetricMeter.getModbusSlaveNatureTable(accessMode) //
);
}
}
2 changes: 2 additions & 0 deletions io.openems.edge.meter.siemens/test/.gitignore
@@ -0,0 +1,2 @@
/bin_test/
/generated/