Skip to content

Commit

Permalink
Implement ShellyPro3Em + fix issue in EdgeConfig (#2567)
Browse files Browse the repository at this point in the history
* ShellyPro3Em

Implements Shelly Pro 3 EM 3-Phase Meter.

https://www.shelly.com/de/products/shop/shelly-pro-3-em-120-a-1

* EdgeConfig: fix parsing of service components

Previously `constains()` would match even partly matching factory IDs. This is fixed by a full string compare for the XML file path.

This fixes an issue with "Samsung.ESS" not showing up, because there is also a factory ID "Samsung.ESS.Grid-Meter".

---------

Co-authored-by: Stefan Feilmeier <[email protected]>
  • Loading branch information
Sn0w3y and sfeilmeier authored Jun 19, 2024
1 parent e51be8d commit ce7f4cf
Show file tree
Hide file tree
Showing 9 changed files with 459 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -495,8 +495,8 @@ private String[] getNatures(Bundle bundle, Manifest manifest, String factoryPid)
var serviceComponents = serviceComponentsString.split(",");

// read Service-Component XML files from OSGI-INF folder
for (String serviceComponent : serviceComponents) {
if (!serviceComponent.contains(factoryPid)) {
for (var serviceComponent : serviceComponents) {
if (!serviceComponent.equals("OSGI-INF/" + factoryPid + ".xml")) {
// search for correct XML file
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

@ObjectClassDefinition(//
name = "Samsung ESS", //
description = "Implements the Sasmung ESS Combined System.")
description = "Implements the Samsung ESS System.")
@interface Config {

@AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@

@Designate(ocd = Config.class, factory = true)
@Component(//
name = "Samsung.ESS", immediate = true, //
name = "Samsung.ESS", //
immediate = true, //
configurationPolicy = ConfigurationPolicy.REQUIRE//
)

@EventTopics({ //
EdgeEventConstants.TOPIC_CYCLE_BEFORE_PROCESS_IMAGE, //
})
Expand Down
1 change: 1 addition & 0 deletions io.openems.edge.io.shelly/readme.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ Compatible with
- https://www.shelly.com/en/products/shop/shelly-3-em[Shelly 3EM]
- Shelly Plug S
- https://www.shelly.com/de/products/shop/shelly-plus-plug-s-1[Shelly Plus Plug S]
- https://www.shelly.com/de/products/shop/shelly-pro-3-em-120-a-1[Shelly Pro 3EM 3-Phase Meter]

https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.io.shelly[Source Code icon:github[]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.openems.edge.io.shelly.shellypro3em;

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

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

@ObjectClassDefinition(
name = "IO Shelly Pro 3EM", //
description = "Implements the Shelly Pro 3EM Energy 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, Production (=default), Consumption")
MeterType type() default MeterType.GRID;

@AttributeDefinition(name = "IP-Address", description = "The IP address of the Shelly device.")
String ip();

String webconsole_configurationFactory_nameHint() default "IO Shelly Pro 3EM [{id}]";

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package io.openems.edge.io.shelly.shellypro3em;

import io.openems.common.channel.Level;
import io.openems.edge.common.channel.Doc;
import io.openems.edge.common.channel.StateChannel;
import io.openems.edge.common.component.OpenemsComponent;
import io.openems.edge.common.channel.value.Value;

public interface IoShellyPro3Em extends OpenemsComponent {

public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
/**
* Phase Sequence Error.
*
* <p>
* Represents an error indicating if the sequence of zero-crossing events is
* Phase A followed by Phase C followed by Phase B. The regular succession of
* these zero-crossing events is Phase A followed by Phase B followed by Phase
* C.
*
* <ul>
* <li>Interface: ShellyPlug
* <li>Type: State
* </ul>
*/
PHASE_SEQUENCE_ERROR(Doc.of(Level.FAULT) //
.text("Incorrect phase sequence. Expected A-B-C but found A-C-B.")),

/**
* Power Meter Failure.
*
* <p>
* Represents a failure in the power meter, potentially leading to inaccurate or
* missing measurements.
*
* <ul>
* <li>Interface: ShellyPlug
* <li>Type: State
* </ul>
*/
POWER_METER_FAILURE(Doc.of(Level.FAULT) //
.text("Power meter failure; unable to record or measure power accurately.")),

/**
* No Load Error.
*
* <p>
* Indicates that the power meter is in a no-load condition and is not
* accumulating the registered energies, therefore, the measured values can be
* discarded.
*
* <ul>
* <li>Interface: ShellyPlug
* <li>Type: State
* </ul>
*/
NO_LOAD(Doc.of(Level.FAULT) //
.text("No load condition detected; the power meter is not accumulating energy.")),

/**
* Slave Communication Failed Fault.
*
* <p>
* Indicates a failure in communication with a slave device, which might affect
* system operations.
*
* <ul>
* <li>Interface: ShellyPlug
* <li>Type: State
* </ul>
*/
SLAVE_COMMUNICATION_FAILED(Doc.of(Level.FAULT) //
.text("Communication with slave device failed."));

private final Doc doc;

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

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

/**
* Gets the Channel for {@link ChannelId#SLAVE_COMMUNICATION_FAILED}.
*
* @return the StateChannel representing communication failure with a slave
* device.
*/
public default StateChannel getSlaveCommunicationFailedChannel() {
return this.channel(ChannelId.SLAVE_COMMUNICATION_FAILED);
}

/**
* Gets the current state of the Slave Communication Failed channel.
*
* @return the Channel {@link Value} indicating whether communication has
* failed.
*/
public default Value<Boolean> getSlaveCommunicationFailed() {
return this.getSlaveCommunicationFailedChannel().value();
}

/**
* Internal method to set the 'nextValue' on
* {@link ChannelId#SLAVE_COMMUNICATION_FAILED} Channel.
*
* @param value the next value indicating communication failure state.
*/
public default void _setSlaveCommunicationFailed(boolean value) {
this.getSlaveCommunicationFailedChannel().setNextValue(value);
}

}
Loading

0 comments on commit ce7f4cf

Please sign in to comment.