Plugin um Webinterface erweitern

  • Eines meiner nächsten Projekte soll die Erweiterung des SerienRecorder Plugins um ein Webinterface sein. Vor Jahren hatte betonme schon mal ein paar Grundlagen geschaffen (auf Basis des AutoTimer Webinterfaces), auf die ich jetzt aufbauen möchte. Im Moment fehlen mir aber noch viele Zusammenhänge und ich hoffe, dass hier jemand ein paar Dinge erklären kann. Bisher habe ich mich als User auch noch nicht wirklich mit dem Webinterface beschäftigt.


    Was ich hoffe richtig verstanden zu haben, dass ein Plugin das Webinterface um zwei Bereiche erweitern kann, einmal API und einmal UI. Dabei ruft der UI Teil dann Funktionen der API auf.
    Im SerienRecorder hat betonme damals Grundlagen für die API geschaffen, dazu wurde mit addExternalChild Funktionen bereitgestellt. Der Code dahinter funktioniert aber, wegen diverser Änderungen am Plugin, inzwischen nicht mehr. Deswegen möchte ich im ersten Schritt die API wieder funktionsfähig machen, ich habe jetzt die Funktionen so umgebaut, dass sie erstmal Dummy Results liefern.


    Meine Fragen sind jetzt:

    1. Wie kann ich die Funktionen testen, ohne dass das Plugin schon ein WebUI hat?
      Ich hab gelesen, dass man wohl /api/<function> aufrufen kann, da bekomme ich aber immer 404 zurück, wobei ich nicht mal genau weiß wie die Funktionen heißen und ob noch ein zusätzlicher Namespace davor muss. addExternalChild( ("serienrecorder", root , "SerienRecorder-Plugin", API_VERSION, False) ) Ist denn "serienrecorder" ein zusätzlicher Namespace (/api/serienrecorder/<function>)?
    2. Es gibt diverse Ordner im Zusammenhang mit dem WebInterface - kann da mal jemand kurz erklären was welcher Ordner enthalten muss?!
      "web-data" scheint quasi der Webserver Root des Plugins zu sein, mit den Templates und Javascript Dateien
    3. Gibt es irgendwo ein Art "Hello World" Plugin für das Webinterface, mit dem man einsteigen kann oder eine Dokumentation?
    4. Gibt es Unterschiede die man bei der Entwicklung berücksichtigen zum OpenWebIf - das Webinterface soll dann möglichst auf allen Boxen laufen?

    Hier ist noch ein Link zur SerienRecorderResource.py die von betonme erstellt wurde: https://github.com/einfall/ser…SerienRecorderResource.py


    Danke fürs Lesen!

  • Es ist zwar schon eine Weile her, seit ich eine solche Erweiterung geschriebne habe, aber ich versuche mal ein paar Dinge niederzuschreiben, welche dir hoffentlich helfen.


    Zuerst musst du sicherstellen, dass das WebInterface deine Erweiterung kennt. Dazu brauchst du einen PluginDescriptor WHERE_SESSIONSTART.


    In der bei sessionstart aufgerufenen Funktion machst du folgendes:

    • Definition von root-Verzeichnis deiner Erweiterung
    • Menüpunkt hinzufügen im WebInterface

    Du kannst natürlich auch noch weitere Verzeichnisse definieren, falls deine Erweiterung diese braucht.


    Hier ein kleiner Codeausschnitt für dein Plugin:

    Code
    root = File(eEnv.resolve("${libdir}/enigma2/python/Plugins/Extensions/SerienRecorder/web-data"))
    root.putChild("web", ScreenPage(session, util.sibpath(__file__, "web"), True) )
    addExternalChild( ("serienrecorder", root, "SerienRecorder-Plugin", "1", True) )


    Das Plugin wird jetzt unter Extras > WebPlugins angezeigt und kann auch über <ip-adresse>/serienrecorder aufgerufen werden. Natürlich fehlt jetzt noch der Inhalt.


    Du hast ausserdem definiert, dass ein Unterverzeichnis web-data dein Rootverzeichnis ist. Da kommen die .htm, .js und .css rein und natürlich allfällige Bilder. Ebenfalls hast du festgelegt, dass es ein Verzeichnis web gibt. Dieses liegt im gleichen Verzeichnis wie web-data. In web liegen die xml-Dateien.


    Nun haben wir diverse Verzeichnisse, aber noch keinen Inhalt. Dieser Inhalt soll von enigma2 ans WebInterface geliefert werden. Es braucht also noch ein paar weitere Anpassungen.


    WebScreens.py (ich nehme jetzt mal ein Beispiel aus meiner Erweiterung):

    Python
    from Plugins.Extensions.MerlinWebInterface.WebComponents.Sources.MerlinMemoryInfo import MerlinMemoryInfo
    
    class MerlinMemoryWebScreen(WebScreen):
        def __init__(self, session, request):
            WebScreen.__init__(self, session, request)
            self["MerlinMemoryInfo"] = MerlinMemoryInfo(session, MerlinMemoryInfo.MEMORY)


    Es gibt also einen WebScreen mit dem Namen MerlinMemoryWebScreen. Die Datensource ist MerlinMemoryInfo und die Funktion MEMORY. Wie du beim Import siehst, sind die Source in einem Unterverzeichnis (WebComponents/Sources).


    Jetzt schauen wir mal die Source an:


    Hier wird beim Aufruf von MEMORY die Funktion getMemoryInfo aufgerufen, die Informationen gesammelt und die Liste zurückgebeben.


    Nun muss die Funktion nur noch aufgerufen werden. Im Verzeichnis web-data brauchst du eine Datei index.htm(l), wleche beim Aufruf deiner Erweiterung geladen wird. Ausserdem braucht es noch ein bisschen javascript.



    In MerlinCore wird festgelegt, dass beim Aufruf von this.meminfo ein MemoryInfoController benötigt wird. Dieser wieder braucht einen MemDevicesListHandler. Dieser legt fest, dass das Template tplMerlinMemoryInfo zu verwenden ist und die Daten vom MemDevicesListProvider kommen. Dort wird die URL aufgerufen und mit renderXML letztlich der Output aus deiner Python-Source verarbeitet.


    Das ganze lässt sich wahrscheinlich auch anders implementieren. So gibt es z.B. im WebBouquetEditor auch nachlesen, wie das gemacht wird. Dort wird ein leicht anderer Ansatz verwendet.


    OpenWebIf kenne ich nicht hinsichtlich Code, gehe aber davon aus, dass es ziemlich identisch ist.

    Gruss
    Dre


    Boxen (im Einsatz): DM920, DM900, DMOne
    Developer Project Merlin - we are OpenSource

  • Und ich dachte, das kann man mal so nebenbei bauen - da ist doch etwas mehr mit vermacht - im Sommer habe ich für solch umfangreiche Sachen keine Zeit - dann muss es wohl bis zum Ende des Jahres warten.


    Danke für deine Codebeispiele und Erläuterungen.

    Dann wird die API eigentlich gar nicht gebraucht, sondern es reicht wenn man entsprechende Module im "WebComponents" Ordner hat?


    Im AutoTimer "sessionstart" sieht das ja so aus:

  • Wie ich geschrieben hatte, gibt es verschiedene Möglichkeiten. Aber auch da hast du JavaScript in web-data.


    WebComponents enthält die Sourcen, welche die Informationen zur Verfügung stellen. Also letztlich ist es ziemlich ähnlich.


    Ganz ohne Aufwand ist das leider alles nicht. Die Architektur ist eher komplex.

    Gruss
    Dre


    Boxen (im Einsatz): DM920, DM900, DMOne
    Developer Project Merlin - we are OpenSource