Projektaufbau (OSGi bundles)

Hallo,

im Rahmen meiner Bachelorarbeit versuche ich aktuell ein OpenEMS Projekt zu entwicklen. Es soll ein E-Scooter intelligent geladen werden. Dafür soll zwischen Netzbetrieb
und einer bereits fertig entwickelten Komponente, die aus einer Solarzelle, einem Akku und einem Pi besteht (ohne OpenEMS), gewechselt werden.
Das Pi stellt alle benötigten Daten bereits per REST Api zur Verfügung. Die Daten des Rollers können wir auf einen kleinen Nodejs Server schicken und dann ebenfalls per REST abfragen.
Die letzte Komponente ist ein weiteres Pi auf dem dann OpenEMS läuft. Dieses dient praktisch als Controller. Hier sollen die Daten zusammenfließen und anhand dieser dann Entscheidungen getroffen werden.
Zudem soll der Benutzer in der Lage sein, über eine UI Daten einzugeben (z.B. maximale Ladezeit). Und dann während des Ladens auch den Zustand des Systems über die OpenEMS Ui einsehen können.

Ich hätte jetzt einige Fragen zum Projektaufbau:

  1. Ich brauche kein openEMS Backend, da ja alles auf einem Gerät läuft, richtig?
  2. Ich habe bereits einen Controller(?) (eigenes osgi-bundle) entwickelt, welcher den Zustand des Relays einstellt (um zwischen den Stromquellen zu wechseln). Das bundle besteht also nur aus einem Pythonfile und Java Klasse mit der Methode um dieses aufzurufen.
    Ist es vom Design her korrekt, dass dies ein eigenes bundle ist (und ein Controller). Wären also alle oben beschriebenen Komponenten ihr eigenes bundle oder sollte mein ganzes Projekt in ein einziges bundle sein?
  3. Zur UI: Sollte ich für den Userinput ein eigenes Projekt machen oder kann ich das einfach über die OpenEMS UI machen? (Oder soll diese nur für Monitoring verwendet werden?)
    Und ich habe wenig über die UI online gefunden, gibt dafür eine Doku oder ähnliches um den Start zu erleichtern?

Und neben dem Aufbau:
4. Gibt es bereits Komponenten, die sich mit dem aktuellen Strompreis beschäftigen (und day-ahead). Da auch anhand des Strompreises entschieden werden soll, wann aus dem Netz geladen wird.

Ich würde mich sehr über eure Antworten und Tipps freuen.

Viele Grüße
Jonas

Hallo Jonas,

das ist ein echt spannendes Bachelor-Projekt! Darf ich fragen, was du studierst und an welcher Hochschule bzw. bei welchem Professor?

zu 1:
Richtig, OpenEMS Backend wird nur benötigt, wenn

  • ein Fernzugang über das Internet ermöglicht werden soll
  • mehrere OpenEMS Edge Systeme gemeinsam überwacht/gesteuert werden sollen

zu 2:
Der Aufbau mit einzelnen Bundles, die nur über API-Schnittstellen (Java-Interfaces) kommunizieren, die wieder um ein separaten Bundles liegen, hat für so ein großes Softwareprojekt viele Vorteile. Es verhindert effektiv Spaghetticode, weil jeder Entwickler ‘gezwungen’ wird, nur gegen Interfaces zu entwickeln. Man sollte also diese Teilung in Schnittstellen (Java Interface) und Implementierung (Java Klasse) bei der Entwicklung von Anfang an im Hinterkopf behalten und berücksichtigen. Dann ist es kein Problem und auch sinnvoll das ganze Projekt in einem einzigen Bundle zu entwickeln. Falls nötig lässt es sich später immer noch sehr einfach refactoren und in separate Bundles aufteilen.

zu 3:
Für das OpenEMS UI gibt es leider noch sehr wenig Dokumentation, aber grundsätzlich wäre es für den Anwendungsfall auch für den Userinput sehr gut geeignet. Ein Beispiel für ein UI-Widget, in dem Daten visualisiert werden und es Eingabemöglichkeiten gibt, ist:

Beispiel der Darstellung:

zu 4:
Ja, wir hatten hier in letzter Zeit einige interne Entwicklungen, die ich gerade als “FEMS Backport” zurück in das OpenEMS Projekt gespielt habe:

Hier ist bereits eine Implementierung für den aWATTar-Tarif enthalten (openems/AwattarProvider.java at develop · OpenEMS/openems · GitHub). Geplant ist, diese Implementierung wieder über das Service-Modell zu implementieren, so dass es verschiedene TimeOfUseTariff Provider gibt, z. B. für Tibber oder STROMDAO Corrently (aktuell in Entwicklung)

Gruß,
Stefan

Hallo Stefan,

erstmal vielen Dank für die Unterstüzung und entschuldigung wegen der späten Antwort. Ich studiere Informatik und die BA ist an der TU München bei Professor Pretschner angemeldet. Meine beiden Betreuer arbeiten bei fortiss und ich soll schöne Grüße von meinem Betreuer Markus Duchon ausrichten.

Ich habe das Projekt jetzt mithilfe der Tipps soweit entwickelt, dass ich zwischen der UI und Edge gut kommunizieren kann. Und es in der Praxis bereits funktioniert. Jetzt muss nur noch ich die Logik der Ladeprozesse in der Edge programmieren.

Dafür wollte ich die timeofuse.api verwenden und dann einige Methoden ähnlich zu denen in controller.ess.timeofusetariff.discharge in meiner Komponente nachbauen. Ich habe dafür in meinem bundle zuerst im bnd-file beim build das bundle importiert und dann einfach wie in controller.ess.timeofusetariff.discharge versucht es zu verwenden, also:

@Reference
private TimeOfUseTariff timeOfUseTariff;

TimeOfUsePrices prices = this.timeOfUseTariff.getPrices();

(Das war zum ausprobieren erstmal alles)
Dann habe ich in der EdgeApp resolved. Das lief auch durch und eclipse hat auch keine Fehler angezeigt.
Allerdings wenn ich die Edge starte, bekomme ich neue Fehlermeldungen, die jetzt auch bundles betreffen die nutze. Ich bekomme schon länger beim Start immer 4 BundleExeption Fehler, aber das hatte die Funktion bisher nicht eingeschränkt.
(Die Fehler kommen auch wenn ich einen neuen Workspace mit neuem geklontem Projekt starte)
Da die Fehlermeldungen sehr lang und daher hier schlecht zu lesen sind, habe ich sie jetzt bis auf die Neue erstmal gekürzt. Im Prizip sind sie gleich aufgebaut nur andere missing requirements.
Die alten Fehler sind:
ERROR: Bundle io.openems.edge.evcs.ocpp.abl [91]
ERROR: Bundle io.openems.edge.evcs.ocpp.common [92]
ERROR: Bundle io.openems.edge.evcs.ocpp.ies.keywatt.singleccs [93]
ERROR: Bundle io.openems.edge.evcs.ocpp.server [94]

jetzt neu ist:

     ERROR: Bundle io.openems.wrapper.eu.chargetime.ocpp [148] Error starting projectfolder/io.openems.wrapper/generated/io.openems.wrapper.eu.chargetime.ocpp.jar (org.osgi.framework.BundleException: Unable to resolve io.openems.wrapper.eu.chargetime.ocpp [148](R 148.0): missing requirement [io.openems.wrapper.eu.chargetime.ocpp [148](R 148.0)] osgi.wiring.package; (osgi.wiring.package=javax.xml.soap) Unresolved requirements: [[io.openems.wrapper.eu.chargetime.ocpp [148](R 148.0)] osgi.wiring.package; (osgi.wiring.package=javax.xml.soap)])
     org.osgi.framework.BundleException: Unable to resolve io.openems.wrapper.eu.chargetime.ocpp [148](R 148.0): missing requirement [io.openems.wrapper.eu.chargetime.ocpp [148](R 148.0)] osgi.wiring.package; (osgi.wiring.package=javax.xml.soap) Unresolved requirements: [[io.openems.wrapper.eu.chargetime.ocpp [148](R 148.0)] osgi.wiring.package; (osgi.wiring.package=javax.xml.soap)]
           at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:4398)
           at org.apache.felix.framework.Felix.startBundle(Felix.java:2308)
           at org.apache.felix.framework.Felix.setActiveStartLevel(Felix.java:1566)
           at org.apache.felix.framework.FrameworkStartLevelImpl.run(FrameworkStartLevelImpl.java:308)
          at java.base/java.lang.Thread.run(Thread.java:832)

Darunter wurde dann noch folgendes geloggt:

2021-11-16 13:53:24,434 [artLevel] INFO  [org.apache.felix.http.jetty   ] Started Jetty 9.4.43.v20210629 at port(s) HTTP:8080 on context path / [minThreads=8,maxThreads=200,acceptors=2,selectors=8]

2021-11-16 13:53:24,566 [artLevel] WARN  [ntmanager.ComponentManagerImpl] bundle io.openems.edge.core:1.0.0.202111161146 (75)[io.openems.edge.core.componentmanager.ComponentManagerImpl(1)] : 
Could not get service from ref [io.openems.edge.common.component.ComponentManager, io.openems.edge.common.component.OpenemsComponent, io.openems.edge.common.jsonapi.JsonApi, org.osgi.service.cm.ConfigurationListener]

2021-11-16 13:53:24,567 [artLevel] WARN  [ntmanager.ComponentManagerImpl] bundle io.openems.edge.core:1.0.0.202111161146 (75)[io.openems.edge.core.componentmanager.ComponentManagerImpl(1)] : 
Could not get service from ref [io.openems.edge.predictor.api.manager.PredictorManager, io.openems.edge.common.component.OpenemsComponent, io.openems.edge.common.jsonapi.JsonApi]

Die Warnings kamen jeweils 2 mal.
Als ich es jetzt nochmal ausgeführt habe (ohne etwas zu ändern), kam etwas neues, wobei es auch nur ca. jedes zweite mal passiert wenn ich es neu starte:

Und jetzt, auch nachdem ich die Änderungen in meiner Komponente rückgängig gemacht habe funktioniert es nicht mehr. Auch in den Runs welche keine Warnings anzeigen. Dadurch, dass die Fehlermeldungen auch beim neuen Aufsetzen noch da sind, weiß ich nicht wirklich was ich an der Stelle machen soll?
Gibt es sowas wie einen Reset für alle generated Sachen, vor Allem die die außerhalb des Projektordners gespeichert werden?
Und war ich mit dem TimeOfUseTariff auf der richtigen Spur? Muss nicht an irgendeiner Stelle die konkrete Awattar oder Corrently Component-Id übergeben werden?

Beste Grüße
Jonas

Hallo Jonas,

vielen Dank für die Hintergrundinfos und freundliche Grüße zurück an Markus Duchon.

Das mit der @Reference für TimeOfUseTariff passt so. In diesem Fall liefert OSGi (via dependency injection) einen beliebigen vorhanden Service, der TimeOfUseTariff implementiert. Das wird im Regelfall nur einer sein; wenn mehrere unterstützt werden sollen, dann würden wir das so machen, wie z. B. bei verschiedenen Controllern. Dafür wird dann auf die @Reference ein target filter gelegt, der nur ganz bestimmte Services akzeptiert (z. B. anhand der Component-ID).

Der Fehler osgi.wiring.package=javax.xml.soap klingt sehr stark nach dem Problem, dass du die falsche Version des Java Development Kit (JDK) einsetzt. Leider erfordert OpenEMS immer noch Java 8. Es wurde zwar schon angefangen, auf eine neuer Version umzustellen (-> hier: Switch to Java 11 by sfeilmeier · Pull Request #1596 · OpenEMS/openems · GitHub), aber wir benötigen dafür erst die neuen Softwarepakete für unser Deployment (z. B. für Debian-Pakete für FEMS/Leaflet/…). Dafür warten wir aktuell auf das Adoptium Projekt (-> Complete new `linuxNew` based packaging · Issue #330 · adoptium/installer · GitHub)

javax.xml.soap wurde mit Java 11 entfernt. Ich gehe davon aus, dass du mit mindestens mit Version 11 baust.

Hier stehen ein paar Tips, wie ein Reset des Workspace durchgeführt und alles neu gebaut werden kann. Das klappt bei mir in der Praxis immer sehr gut (ist aber mit neuen Versionen von Eclipse und bndtools seltener notwendig geworden): Build in Eclipse fails with many errors - #2 by stefan.feilmeier

Gruß,
Stefan