Understanding queryHistoricData

Liebe Community

Derzeit haben wir in unserem Projekt mehrere Prognosealgorithmen, die bereits von OpenEMS unabhängig arbeiten. Aber natürlich brauchen wir die prognostizierten Daten in OpenEMS, damit die Controller mit ihnen für weitere Optimierungen arbeiten können.

Ich habe diese Standardfunktion aus der Timdata-Interface herausgefunden:queryHistoricData (z.B. in L331 InfluxConnector). Ich denke, das ist genau das, wonach ich suche. Ich kann es so programmieren, dass ich n*Datenzeilen aus der DB in einem einzigen Schritt erhalte. Aber ich finde es schwer zu verstehen, wie die Funktion außerhalb von einem anderen Bundle verwendet wird.

Ich habe auch eine Implementierung gefunden PersistenceModelPredictorImpl, die diese Funktion verwendet. Was ich finde es schwer zu verstehen ist, wie diese implementaion weiß, welche Timedata Source oder edgeId mit zu verbinden (Angesichts der Tatsache, dass wir mit mehreren MSSQL DBs verbinden möchten, da die Prognosen auf verschiedenen Servern laufen, also haben wir mehre Timedata instance). In der Implementierung werden die Timedata nur initialisiert, ohne weitere Details (siehe Initialization Timedata)

Ein weiterer Punkt, der für mich schwer zu verstehen ist, ist, ob OpenEMS bereits sicherstellt, dass sich Anfragen nicht überschneiden, wenn dieselbe Funktion queryHistoricData von verschiedenen Bundles zur gleichen Zeit verwendet wird, d.h. als paralleler Prozess.

Ich hoffe, ich konnte mein Problem erklären. Ich wäre Ihnen sehr dankbar für Ihre Hilfe.

Danke
Laksh

Hallo Laksh,

ich kenne euren Systemaufbau nicht, aber OpenEMS unterscheidet eigentlich zwischen einem Timedata service, der historische Daten zur Verfügung stellt und einem Predictor, der prognostizierte Daten liefert.

Timedata wird z. B. verwendet, um im OpenEMS UI historische Daten anzuzeigen. Was du beschreibst klingt für mich eher nach Predictor, aber es kann natürlich sein, dass auch der aktuell nicht zu 100 % das abdeckt, was ihr braucht. Wenn ihr mit Timedata zurecht kommt, ist das also auch ok.

Wie @Reference in OpenEMS mit OSGi Declarative Services funktioniert, habe ich an anderer Stelle erklärt:

Diesen @Reference-Annotationen kann man auch einen target Filter geben. Dieser sorgt dann dafür, dass nur ganz bestimmte Services injiziert werden.

Hier etwas zu target in der Spezifikation:
http://docs.osgi.org/specification/osgi.cmpn/7.0.0/service.component.html#service.component-target.property

OpenEMS verwendet an einigen Stellen diese expliziten Filter. Beispiel: der “ESS Fix Active Power Controller” arbeitet immer mit einem anhand seiner Component-ID klar definierten Speichersystem. Dazu schreibt die Methode OpenemsComponent.updateReferenceFilter() die target Property so, dass nur die Komponente mit dieser ID akzeptiert wird.

Das gleiche Prinzip lässt sich auch auf Timedata anwenden, wenn ein ganz bestimmter Timedata Service notwendig ist.

War das verständlich erklärt?

Gruß,
Stefan

Hallo Stefan,

danke für die ausführliche Antwort.

Ich habe das Konzept im Allgemeinen verstanden. Was du meinst ist, dass wir in der Komponente @ProviderType, d.h. in unserem Fall die Klasse, die die “Timedata” Interface implementiert, angeben können, welche Komponenten-Ids mit der gegebenen API interagieren dürfen, oder ist es andersherum?

Ich lade eine Skizze hoch, so ist es für mich einfacher, es zu verstehen.

Vielen Dank
Laksh

Hallo Laksh,

ich versuche es auch mit einer Grafik zu verdeutlichen:

Links sind die Provider definiert:

  • das Interface Timedata
  • die beiden Beispiel-Implementierungen (Klassen) TimedataInfluxDB und TimedataRRD4j implementieren Timedata
  • davon gibt es insgesamt drei Objeke/Instanzen mit den Component-IDs timedata0, timedata1 und timedata2

Rechts sind zwei beispielhafte Instanzen mit Referenzen auf Timedata. Oben ohne target filter, unten mit targetfilter (z. B. generiert durch einen Aufruf von OpenemsComponent.updateReferenceFilter().

Im Beispiel oben wird das OSGi Framework einen zufälligen Service injizieren, der Timedata implementiert - also timedata0, timedata1 und timedata2

Im Beispiel unten sagt der target filter, dass der zu injizierende Service Timedata implementieren muss und die id=timedata1 sein muss. Somit wird explizit genau timedata1 injiziert. Sollte timedata1 nicht vorhanden sein, so kann diese MyController-Instanz nicht aktiviert werden, weil nicht alle Referenzen aufgelöst werden können.

Ist es jetzt klarer - oder habe ich deine Frage noch nicht richtig verstanden?

Gruß,
Stefan