Skip to content

Commit

Permalink
Implement Eastron SDM120 meter & update existing SDM360 (#2554)
Browse files Browse the repository at this point in the history
Co-authored-by: Hans Krämer <[email protected]>
Co-authored-by: Stefan Feilmeier <[email protected]>
  • Loading branch information
3 people authored Apr 30, 2024
1 parent 021e674 commit 49c8e94
Show file tree
Hide file tree
Showing 21 changed files with 471 additions and 35 deletions.
4 changes: 2 additions & 2 deletions io.openems.edge.application/EdgeApp.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,9 @@
bnd.identity;id='io.openems.edge.meter.camillebauer.aplus',\
bnd.identity;id='io.openems.edge.meter.carlo.gavazzi.em300',\
bnd.identity;id='io.openems.edge.meter.discovergy',\
bnd.identity;id='io.openems.edge.meter.eastron',\
bnd.identity;id='io.openems.edge.meter.janitza',\
bnd.identity;id='io.openems.edge.meter.kdk',\
bnd.identity;id='io.openems.edge.meter.microcare.sdm630',\
bnd.identity;id='io.openems.edge.meter.phoenixcontact',\
bnd.identity;id='io.openems.edge.meter.plexlog',\
bnd.identity;id='io.openems.edge.meter.pqplus',\
Expand Down Expand Up @@ -321,9 +321,9 @@
io.openems.edge.meter.camillebauer.aplus;version=snapshot,\
io.openems.edge.meter.carlo.gavazzi.em300;version=snapshot,\
io.openems.edge.meter.discovergy;version=snapshot,\
io.openems.edge.meter.eastron;version=snapshot,\
io.openems.edge.meter.janitza;version=snapshot,\
io.openems.edge.meter.kdk;version=snapshot,\
io.openems.edge.meter.microcare.sdm630;version=snapshot,\
io.openems.edge.meter.phoenixcontact;version=snapshot,\
io.openems.edge.meter.plexlog;version=snapshot,\
io.openems.edge.meter.pqplus;version=snapshot,\
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package io.openems.edge.meter.api;

import static io.openems.edge.meter.api.SinglePhase.L1;
import static io.openems.edge.meter.api.SinglePhase.L2;
import static io.openems.edge.meter.api.SinglePhase.L3;

import java.util.function.Function;

import org.osgi.annotation.versioning.ProviderType;
Expand Down Expand Up @@ -45,7 +49,7 @@ public Doc doc() {
* @param meter the {@link SinglePhaseMeter}
*/
public static void calculateSinglePhaseFromActivePower(SinglePhaseMeter meter) {
SinglePhaseMeter.calculateSinglePhaseFromActivePower(meter, SinglePhaseMeter::getPhase);
calculateSinglePhaseFromActivePower(meter, SinglePhaseMeter::getPhase);
}

/**
Expand All @@ -70,9 +74,52 @@ public static <METER extends ElectricityMeter> void calculateSinglePhaseFromActi
Function<METER, SinglePhase> phaseProvider) {
meter.getActivePowerChannel().onSetNextValue(value -> {
var phase = phaseProvider.apply(meter);
meter.getActivePowerL1Channel().setNextValue(phase == SinglePhase.L1 ? value : null);
meter.getActivePowerL2Channel().setNextValue(phase == SinglePhase.L2 ? value : null);
meter.getActivePowerL3Channel().setNextValue(phase == SinglePhase.L3 ? value : null);
meter.getActivePowerL1Channel().setNextValue(phase == L1 ? value : null);
meter.getActivePowerL2Channel().setNextValue(phase == L2 ? value : null);
meter.getActivePowerL3Channel().setNextValue(phase == L3 ? value : null);
});
}

/**
* Initializes Channel listeners for a {@link SinglePhaseMeter}.
*
* <p>
* Sets the correct value for {@link ChannelId#REACTIVE_POWER_L1},
* {@link ChannelId#REACTIVE_POWER_L2} or {@link ChannelId#REACTIVE_POWER_L3}
* from {@link ChannelId#REACTIVE_POWER} by evaluating the configured
* {@link SinglePhase} via {@link SinglePhaseMeter#getPhase()}.
*
* @param meter the {@link SinglePhaseMeter}
*/
public static void calculateSinglePhaseFromReactivePower(SinglePhaseMeter meter) {
calculateSinglePhaseFromReactivePower(meter, SinglePhaseMeter::getPhase);
}

/**
* Initializes Channel listeners for a {@link SinglePhaseMeter}.
*
* <p>
* Use this method if it is not known at compile time, that the
* {@link ElectricityMeter} is a {@link SinglePhaseMeter}, i.e. it is not
* implementing {@link SinglePhaseMeter}.
*
* <p>
* Sets the correct value for {@link ChannelId#REACTIVE_POWER_L1},
* {@link ChannelId#REACTIVE_POWER_L2} or {@link ChannelId#REACTIVE_POWER_L3}
* from {@link ChannelId#REACTIVE_POWER} by evaluating the provided
* {@link SinglePhase}.
*
* @param <METER> type that extends {@link ElectricityMeter}
* @param meter a {@link ElectricityMeter}
* @param phaseProvider a provider for {@link SinglePhase}
*/
public static <METER extends ElectricityMeter> void calculateSinglePhaseFromReactivePower(METER meter,
Function<METER, SinglePhase> phaseProvider) {
meter.getReactivePowerChannel().onSetNextValue(value -> {
var phase = phaseProvider.apply(meter);
meter.getReactivePowerL1Channel().setNextValue(phase == L1 ? value : null);
meter.getReactivePowerL2Channel().setNextValue(phase == L2 ? value : null);
meter.getReactivePowerL3Channel().setNextValue(phase == L3 ? value : null);
});
}

Expand All @@ -88,7 +135,7 @@ public static <METER extends ElectricityMeter> void calculateSinglePhaseFromActi
* @param meter the {@link SinglePhaseMeter}
*/
public static void calculateSinglePhaseFromCurrent(SinglePhaseMeter meter) {
SinglePhaseMeter.calculateSinglePhaseFromCurrent(meter, SinglePhaseMeter::getPhase);
calculateSinglePhaseFromCurrent(meter, SinglePhaseMeter::getPhase);
}

/**
Expand All @@ -112,9 +159,9 @@ public static <METER extends ElectricityMeter> void calculateSinglePhaseFromCurr
Function<METER, SinglePhase> phaseProvider) {
meter.getCurrentChannel().onSetNextValue(value -> {
var phase = phaseProvider.apply(meter);
meter.getCurrentL1Channel().setNextValue(phase == SinglePhase.L1 ? value : null);
meter.getCurrentL2Channel().setNextValue(phase == SinglePhase.L2 ? value : null);
meter.getCurrentL3Channel().setNextValue(phase == SinglePhase.L3 ? value : null);
meter.getCurrentL1Channel().setNextValue(phase == L1 ? value : null);
meter.getCurrentL2Channel().setNextValue(phase == L2 ? value : null);
meter.getCurrentL3Channel().setNextValue(phase == L3 ? value : null);
});
}

Expand All @@ -130,7 +177,7 @@ public static <METER extends ElectricityMeter> void calculateSinglePhaseFromCurr
* @param meter the {@link SinglePhaseMeter}
*/
public static void calculateSinglePhaseFromVoltage(SinglePhaseMeter meter) {
SinglePhaseMeter.calculateSinglePhaseFromVoltage(meter, SinglePhaseMeter::getPhase);
calculateSinglePhaseFromVoltage(meter, SinglePhaseMeter::getPhase);
}

/**
Expand All @@ -154,9 +201,9 @@ public static <METER extends ElectricityMeter> void calculateSinglePhaseFromVolt
Function<METER, SinglePhase> phaseProvider) {
meter.getVoltageChannel().onSetNextValue(value -> {
var phase = phaseProvider.apply(meter);
meter.getVoltageL1Channel().setNextValue(phase == SinglePhase.L1 ? value : null);
meter.getVoltageL2Channel().setNextValue(phase == SinglePhase.L2 ? value : null);
meter.getVoltageL3Channel().setNextValue(phase == SinglePhase.L3 ? value : null);
meter.getVoltageL1Channel().setNextValue(phase == L1 ? value : null);
meter.getVoltageL2Channel().setNextValue(phase == L2 ? value : null);
meter.getVoltageL3Channel().setNextValue(phase == L3 ? value : null);
});
}

Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>io.openems.edge.meter.microcare.sdm630</name>
<name>io.openems.edge.meter.eastron</name>
<comment></comment>
<projects>
</projects>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Bundle-Name: OpenEMS Edge Meter Microcare SDM 630 Smart Meter
Bundle-Name: OpenEMS Edge Meter Eastron SDM 630 Smart Meter
Bundle-Vendor: Microcare (Destrier Electronics Pty Ltd)
Bundle-Version: 1.0.0.${tstamp}
Bundle-License: Proprietary (for now)
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
= Microcare SDM 630 Meter
= Eastron/Microcare SDM 630 and 120 Meter

This implementation is functionally compatible with a number of energy meters with the name "SDM 630".
This implementation is functionally compatible with a number of energy meters with the names:

- SDM 630 and
- SDM 120
Implemented Natures:
- ElectricityMeter

https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.meter.microcare.sdm630[Source Code icon:github[]]
https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.meter.eastron[Source Code icon:github[]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package io.openems.edge.meter.eastron.sdm120;

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

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

@ObjectClassDefinition(name = "Meter Eastron SDM 120", //
description = "Implements the Eastron SDM120 meter.")
@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 = "Grid (default), Production, Consumption")
MeterType type() default MeterType.GRID;

@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 = "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 = "Phase", description = "Which Phase is this Meter connected to?")
SinglePhase phase() default SinglePhase.L1;

@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 Eastron SDM 120 [{id}]";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.openems.edge.meter.eastron.sdm120;

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;
import io.openems.edge.meter.api.SinglePhaseMeter;

public interface MeterEastronSdm120 extends SinglePhaseMeter, ElectricityMeter, OpenemsComponent, ModbusSlave {

public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
REACTIVE_PRODUCTION_ENERGY(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.VOLT_AMPERE_REACTIVE_HOURS)), //
REACTIVE_CONSUMPTION_ENERGY(Doc.of(OpenemsType.INTEGER) //
.unit(Unit.VOLT_AMPERE_REACTIVE_HOURS)), //
;

private final Doc doc;

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

@Override
public Doc doc() {
return this.doc;
}
}

}
Loading

0 comments on commit 49c8e94

Please sign in to comment.