Skip to content

Ablauf des Seitenaufbaus und Datenflusses

wvhn edited this page May 6, 2020 · 3 revisions

von @smai im Forum beschrieben:

  1. Beim allerersten Aufruf wird am Ende von /pages/base/root.html der Backend-Treiber mit Adresse und Port in der Funktion io.init als io initialisiert (also z.B. /driver/io_smarthome.py.js).

  2. Beim erstmaligen Aufruf jeder Seite werden die JavaScript-Objekte der Widgets erzeugt. Für die aktuell integrierten Widgets sind dies jQuery Mobile Widgets, welche in /widgets/*.js definiert sind und durch jQuery Mobile automatisch initialisiert werden. In früheren Versionen und z.T heute noch bei selbst erstellten Widgets wurden in /widgets/widget.js bei onpagebeforeshow Events an die DOM-Objekte gebunden (mehr Details zum Unterschied unter Punkt 6).

  3. Bei jedem Wechsel zwischen Seiten (also erstmalig oder späteres Zurückkehren) wird io.run() aufgerufen (/pages/base/root.html Zeile 196).

  4. In io.run() von /driver/io_smarthome.py.js Zeilen 78 - 84 geschehen zwei Aufrufe:

    • widget.refresh() von /lib/base/base.js 1532 bis 1543 (v2.9), welches die Widgets auf der Seite mit bereits früher erhaltenen Werten aus dem Backend befüllt (wie das genau geschieht steht in Schritt 6).
    • io.monitor() von /driver/io_smarthome.py.js 238-269, welches in SmartHomeNG alle Items abonniert, welche auf der aktuellen Seite vorkommen (auch bereits vorhandene - dass diese nicht doppelt abonniert werden, muss das Backend sicherstellen). Die Plots werden hier separat behandelt, weil diese anders abonniert werden müssen.
  5. SmartHomeNG sendet dann asynchron die abonnierten Daten, welche in io.socket.onmessage von /driver/io_smarthome.py.js 143-212 empfangen werden und an widget.update() in /lib/base/base.js 1470-1510 (v2.9) übergeben werden.

  6. widget.update() unterscheidet zwischen den aktuellen Widgets (welche ich u.A. aus Performancegründen umgebaut hatte) und veralteten aus externen Quellen:

    • Für aktuelle Widgets wird die update-Methode des Basis-Widgets aufgerufen, welche in /base/base.js 2019-2035 (v2.9) implementiert ist. Diese ruft dann wiederum die Implementation _update() jedes einzelnen Widgets mit den für dieses Widget benötigten Item-Werten auf.
    • Ältere Widgets müssen für jedes Item einzeln im DOM gesucht werden und dann das per jQuery angebundene update-Event mit den benötigten Item-Werten aufgerufen werden.

Bei den Plots kommt noch etwas hinzu: Beim ersten Datenempfang wird bei diesen erst Highcharts initialisiert und mit den vollständig beladen. Bei späteren Updates kommen werden nur einzelne Datenpunkte angefügt. Für veraltete Widgets geschieht diese Unterscheidung in /lib/base/base.js 1164, für die aktuellen in /lib/base/base.js 1633-1636.

von @smai im Forum

Die Nutzung von Items in den Widgets ist recht einfach: Das HTML-Tag muss ein Attribut namens data-item haben, welches den Namen des Items enthält. Wenn mehrere Items verwendet werden, sollten diese per Twig-Funktion {{ implode(itemliste) }} eingefügt werden. Der Wert der Items wird dann an die update-Methode des Widgets übergeben und kann dort verarbeitet werden.

Anstelle io.write() sollte in Widgets übrigens this._write(value, itemindex) implementiert in lib/base/base.js:2054 verwendet werden. Der Parameter itemindex bezieht sich dabei auf die Nummer des items aus dem HTML-Attribut data-item. Wenn es nur ein Item in diesem Widget gibt, kann er ganz weggelassen werden.

Obwohl der interne Datenfluss für die Entwicklung von Widgets nicht relevant ist, hier die Erläuterung fürs Interesse. Achtung: Keine dieser Methoden sollte direkt aufgerufen werden, weil ich das nicht als externes API ansehe und dies damit jederzeit ändern kann.

In pages/base/root.html:196 wird bei jedem Seitenwechsel io.run() ausgeführt, welches wiederum io.monitor() aufruft. Diese fragt dann per widget.listeners() in lib/base/base.js:L1594-L1609 die auf der aktuellen Seite benötigten Items ab und sendet den monitor Befehl per Websocket an SmartHomeNG. Dies bewirkt, dass SmartHomeNG die Werte dieser Items - wie auch jede spätere Wertänderung - auf dem Websocket zurücksendet. Die empfangenen Daten werden in io.socket.onmessage verarbeitet und per widget.update() in den Buffer geschrieben. Dort wird auch die update-Methode der betroffenen Widgets aufgerufen. Weil im Fall von SmartHomeNG die Änderungen automatisch gesendet wird (= push), ist io.read() leer. Diese wird nur bei Backends benötigt, welche dies nicht unterstützen und deshalb regelmässig abgefragt werden müssen (= pull).

Wie man sieht, ist das ganze mMn unnötig kompliziert, weshalb ich das in einer späteren Version umbauen möchte. Genau deshalb sollte nichts davon direkt verwendet werden. Wenn man unbedingt etwas aus dem Buffer lesen will, sollte dies per widget.get() abgefragt werden. Ich sehe aber aktuell keinen vernünftigen Anwendungsfall dafür.