Variablen aus SunSpec-Tabellen der SMA WR Modbus-Implementierung auswählen

Hallo,
Ich versuche, eine angepasste Version der Datenlogging-Funktion des SMA Wechselrichters (Sunny Tri Power 25000TL) zu implementieren. Ich weiß, dass es bereits eine Implementierung für diesen WR gibt, die wie folgt aussieht.

Soweit ich verstehe, enthält die ImmutableMap (erstellt für Influx DB INSERT) alle Variablen aus der jeweiligen MODEL/SunSpec Tabelle. Wenn wir zum Beispiel

Map.put(DefaultSunSpecModel.S_101, Priority.HIGH)

verwenden, werden alle Variablen in den SunSpec Tabelle 101 zu dem POINT hinzugefügt.

Ich möchte aber nur ein paar Variablen aus den SunSpec-Tabellen auswählen und sie zur MAP hinzufügen, damit ich nicht die gesamte SunSpec 101-Tabelle in meiner DB speichern muss. Glauben Sie, dass es eine Möglichkeit gibt, das zu tun? oder ist es bereits irgendwo anders gemacht. Vielen Dank im Voraus.

viele Grüße
Laksh

Hallo Laksh,

dafür gibt es bisher leider keine Möglichkeit, ohne tiefer in den (relativ komplexen) SunSpec-Code einzusteigen. Der jetzige Filter greift hier:

Ein detaillierterer Filter müsste dann hier eingreifen:

Alternativ wäre es auch möglich, den Filter bei der Datenbank-Komponente zu machen. Alle Elemente eines SunSpec-Blocks werden sowieso mit nur einem Modbus-Request abgeholt, so dass es für die Performance eher schlechter wäre, dort Löcher zu haben (nicht-durchgängige Modbus-Requests teilt die Modbus-Bridge in mehrere einzelne Requests auf)

Hier ein Beispiel für einen Filter auf Datenbank/Timedata-Ebene:

Gruß,
Stefan

Hallo Stefan,

Vielen Dank für deine schnelle Antwort. Tut mir leid, dass ich mich so spät melde. Ich wollte versuchen, OpenEMS mit dem WR zu verbinden, den wir hier in unserem Labor haben, und mich dann wieder bei dir melden. Aber leider war es aufgrund der COVID-Vorschriften nicht einfach.

Allerdings stimme ich mit deinem letzten Punkt vollkommen, dass es am besten ist, die benötigten Werte auf der DB-Seite des Codes zu filtern. Was mir noch nicht ganz klar ist, wie kann ich einen bestimmten Kanal aus einer Komponente auslesen.

Zum Beispiel habe ich die Komponente SmaPvInverter mit nur einer sunspec Tabelle konfiguriert - 101

private static final Map<SunSpecModel, Priority> ACTIVE_MODELS = ImmutableMap.<SunSpecModel, Priority>builder()
		.put(DefaultSunSpecModel.S_101, Priority.HIGH)
		.build();

Nun möchte ich z.B. nur den Strom der Phase 1 lesen (Kanalname: S101_APH_A, Register: 40189), wie kann ich dieses Detail extrahieren. Zum Beispiel ist der folgende Code nur für die Handhabung von PV-Daten zuständig:

this.componentManager.getEnabledComponents()
				 .stream().filter(c -> c instanceof SmaPvInverter)
				 .forEach(component -> {
						lastestValue_S101_APH_A = ???? component.channel("S101_APH_A").getValue()
				 }) 

Gibt es im Code eine Möglichkeit, lastestValue_S101_APH_A direkt zu erhalten, wie ich denke??
Die andere Möglichkeit, die ich bereits im Kopf habe, ist, durch alle Kanalnamen zu schleifen und meine lokalen Variablen zu setzen, wenn die component.channel.address() gleich "S101_APH_A" ist, zum Beispiel. Aber ich bin mir nicht sicher, ob dies ein optimaler Weg ist, um es zu tun. Ich habe mir auch die RRD4J-Implementierung angesehen, so habe ich verstanden, dass wir den letzten Wert von einem Kanal abrufen können, aber auch dort war nicht klar, wie man einen bestimmten Kanal abrufen kann.

Deine Kommentare wären hier sehr hilfreich. Vielen Dank im Voraus.

viele Grüße
Laksh

Hallo Laksh,

kein Problem! :slight_smile:

Um den Channel zu bekommen gibt es zwei Möglichkeiten:

  1. Innerhalb von AbstractOpenemsSunSpecComponent gibt es eine protected-Methode getSunSpecChannel(). (Diese könnte man eigentlich auch public machen…)
component.getSunSpecChannel(DefaultSunSpecModel.S101.APH_A);
  1. Von außen über die normale channel()-Methode:
component.channel(DefaultSunSpecModel.S101.APH_A.getChannelId());

Für einen typisierten Zugriff dann z. B.:

IntegerReadChannel aPhAChannel = component.channel(DefaultSunSpecModel.S101.APH_A.getChannelId());
int aPhA = aPhAChannel.value().getOrError();

Alternativ zu getOrError() eine der anderen Channel-Methoden, wie hier beschrieben: Core concepts & terminology :: Open Energy Management System

Gruß,
Stefan

Hallo Stefan,
Ich versuche gerade, die Werte abzulesen, wie du gesagt hast. Aber ich erhalte eine Exception:

Exception: Channel [S101A] is not defined for ID [pvInverter0]. Implementation [io.openems.edge.pvinverter.sma.SmaPvInverter]

Mein funktionalität war durch eine void function, wie folgt:

    public void PVDataHandler(String componentId) throws IllegalArgumentException, OpenemsNamedException {
        AbstractOpenemsSunSpecComponent component =  this.componentManager.getComponent(componentId); 
	    IntegerReadChannel AC_Current = component.channel(DefaultSunSpecModel.S101.A.getChannelId());
	    log.info("Value read from S101.A channel: " + AC_Current.value().getOrError());
	}

Ich bin mir nicht sicher, was ich falsch mache. kannst du mir hier helfen.

viele Grüße
Laksh

Hallo Laksh,

die Methode sieht soweit ok aus. Allerdings wird der Channel erst angelegt, wenn der entsprechende SunSpec-Block eingelesen wurde. Wann rufst du die Funktion auf? Kannst du mal die Methode onSunSpecInitializationCompleted() überschreiben und dort die deine PVDataHandler()-Methode aufrufen? Zu dem Zeitpunkt sind dann alle SunSpec-Channel verfügbar.

Hallo Stefan,

danke für deinen Tipp. Es funktioniert jetzt. Du hattest Recht, ich habe den Kanal aufgerufen, sobald ich die SmaPvInverter-Komponente aktiviert habe, deshalb gab es einen Fehler.

Und anstatt meinen PVDataHandler direkt in die Methode onSunSpecInitializationCompleted() zu kodieren, habe ich die Methode isSunSpecInitializationCompleted() verwendet und die PV-Datenübergabe übersprungen, bis dieses Flag True war.

Meine Methode sieht also wie folgt aus:

public void PVDataHandler(String componentId) throws OpenemsNamedException {
	AbstractOpenemsSunSpecComponent component = this.componentManager.getComponent(componentId);
	if (component.isSunSpecInitializationCompleted()) {
		IntegerReadChannel AC_Current = component.channel(DefaultSunSpecModel.S103.A.getChannelId());
		log.info("Value read from S101.A channel: " + AC_Current.value().getOrError());
	} else {
		log.info("SunSpec model not completely intialized. Skipping PVDataHandler");
		return;
	}
	
}

viele Grüße
Laksh

1 Like