FHEMWEB: Wie den Output einer eigenem FW_detailFn/FW_summaryFn aktualisieren?

Begonnen von Markus Bloch, 06 Juni 2015, 00:22:52

Vorheriges Thema - Nächstes Thema

Markus Bloch

Hallo zusammen,

unter http://forum.fhem.de/index.php/topic,27218.msg301156.html#msg301156 habe ich einen ersten Entwurf einer Anrufliste gepostet an dem ich aktuell arbeite. Nun stellt sich mir die Frage, wie kann man die Anrufliste Event-gesteuert im Browser aktuell halten (Longpoll/Inform)?

Ich wollte gerne bewusst auf Readings verzichten und der entsprechenden hohen Anzahl an Events die damit verbunden wäre eine Anrufliste aktuell zu halten. Daher fällt der übliche Mechanismus mit den Inform-Id's im HTML Quelltext raus.

Ich würde mir folgendes vorstellen:

Man setzt in seinem modulspezifischen Quelltext an einer entsprechenden Stelle wie bisher eine InformId auf die der Longpoll-Mechanismus entsprechend normal greift. Als weiteres setzt man als Attribut einen Javascript-Handler oder Funktionsname, der dann vom Longpollmechanismus gestartet wird, sobald ein Event auf die InformId im gleichen Tag passt.

Dann würde ich über diese eigene Javascript-Funktion nur den entsprechenden modulspezifischen Content durch das Ergebnis von FW_cmd(get <name> html...) ersetzen. Damit würde dann nur dieser Teil entsprechend neu generiert und auf der Seite aktualisiert werden, sobald für das entsprechende Device ein Event durch Inform behandelt wird.

Im Modul würde ich bei einer Aktualisierung der Daten einen Trigger starten der diesen Vorgang im Browser dann anstößt.

Wäre so etwas möglich oder gibt es da Alternativen sich an den Longpoll-Mechanismus anzuhängen mit modulspezifischem HTML-Code der aktualisiert werden soll?

Vielen Dank

Gruß

Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

justme1968

es gibt mindestens drei möglichkeiten das umzusetzen:

- du kannst den longpoll mechanismus direkt verwenden. das ganze baut ja nicht auf readings auf sondern auf events. die nötigen events kannst du mit trigger oder commandTrigger erzeugen. ich bin der meinung das man aber diese events nur erzeugen sollte wenn das entsprechende device auch gerade angezeigt wird.  so macht es readingsGroup. je nach dem wo du die informId setzt kannst du beliebige html teile austauschen. eine zelle, eine zeile oder die ganze tabelle. du kannst aber nur bereits vorhandne elemente ändern.

- die zweite möglichkeit ist weiterhin trigger bzw. commandTrigger zu verwenden aber die nachrichten in einem eigenen handler zu verarbeiten. das mache ich mir readingsHistory. hier wird initial die tabelle im perl code erzeugt und dann nur nur einzelne neue zeilen zum browser geschickt wo sie dann in dem eigenen handler jeweils am anfang eingefügt werden.  in readingsHistory ist das ganze noch nicht auf die neue methode umgestellt sondern verwendet noch den 'legacy mode' von vor der javascript umstellung. die neue methode ins aber im prinzip gleich. der vorteil dieser variante ist das du nur noch nakte daten an den browser sendest und dieser html erzeugt bzw. den dom baum per jquery manipuliert. hier kannst du auch elemente löschen oder neu einbauen.

auf perl seite musst du nicht html tags zusammen bauen und hast auch keine doppelte funktionalität auf js seite. das erzeugen der html codes auf js seite machen die fhemweb widgets wie slider, colorpicker und die jzsu widgets. readingsHistory muss ich noch darauf umstellen.

- die dritte möglichkeit ist es die nachrichten nicht per event bzw. trigger/commandTrigger zu erzeugen sondern per FW_directNotify abzuschicken. die daten werden dann intern etwas effizienter behandelt und sind nicht im eventMonitor zu sehen. du kannst hier auch direkt json versenden statt nur strings. das handling auf browser seite wäre identisch zu variante zwei.

gruss
  andre

ps: ich kann dir auch anbieten code teile aus der readingsGroup wieder bzw. mit zu verwenden. ich habe schon angefangen zu implementieren das es möglich ist vom readingsGroup modul abgeleitete module zu realisieren die eigene logik haben. daten aufzubereiten die aber alle layout und mapping möglichkeiten des parent moduls wieder verwenden. d.h. der endanwender muss nicht zwei devices definieren und braucht auch das layout nicht zu konfigurieren wenn er das nicht will. auch die möglichkeit wie zeilen auf und zu zu klappen oder das mapping von werten zu icons wären automatisch mit dabei.
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Markus Bloch

Hallo Andre,

Vielen Dank für die Hilfe. Hätte nicht gedacht, dass es so viele Möglichkeiten gibt dieses Problem zu lösen.

Zu Variante 1: Klingt für mich ziemlich simple, so wie ich das verstehe würdest du dann z.B. auf das <table>-Tag eine informId setzen und im Modul bei Änderungen einen Trigger erzeugen mit dem entsprechenden Namen und dem gesamten HTML-Quelltext hinterher der unterhalb von <table> aktualisiert werden soll. Ist denke ich die einfachste Methode die mit dem bestehenden Funktionsumfang klar kommt. Klappt das auch, wenn man da eine gesamte Tabelle in HTML drüber jagt wegen Sonderzeichen/Anführungszeichen/usw.?

Zu Variante 2: Kannst du mir hier mal kurz das Zusammenspiel zwischen Modul und Javascript im Browser erklären. Ich hab in deinem Modul gesehen wie du einzelne neue Datensätze übergibst  ("history: "...) und alte Zeilen Löschst ("clear: "...). Allerdings habe ich noch nicht den genauen Weg von den Events zu deinem Event-Handler verstanden. Du registrierst diesen als Widget mit "updateLine". Wo genau setzt du diesen Verweis auf dein Handler im HTML und wie sind die Übergabeparameter an den Handler in diesem Fall?

Zu Variante 3: Der Unterschied ist soweit klar. Du meinst warscheinlich FW_directNotify und nicht directInform. Wird das Event dann nicht an alle Clients geschickt, egal ob sie das Event "bestellt" haben oder nicht? Bin mir gerade nicht sicher an welcher Stelle der Inform-Filter greift.

Vielen Dank für deine Hilfe

Viele Grüße

Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

justme1968

1. ja. genau. wenn du die komplette tabelle ersetzt musst du eventuell aufpassen das der sende buffer nicht überläuft aber das wäre das prinzip. wenn es mit bestimmten zeichen probleme gibt siehst du das recht schnell auf der js konsole. dann musst du je nach stelle per url, html oder json regeln escapen.

2. an updateLine wird jeweils für alle nachrichten die über das longpoll socket rein kommen aufgerufen. die routine ist selber dafür zuständig rauszufinden ob die nachricht für sie bestimmt war oder nicht. die updateLine routine ist die 'legacy' variante. die neue variante sollte setValueFn verwenden.

der js code steht jeweils in .../www/pgm2/fhemweb_... und wird automatisch geladen. da es zur nachricht keine passende informId gibt wird hier von fhemweb nichts automatisch gemacht. das passiert dann in deinem updateLine handler.

3. ist oben (neben ein paar anderen dingen) auch schon korrigiert :).


bei allen varianten werden die daten an alle clients geschickt. longpoll ist eher eine art bus als eine punkt zu punkt verbindung. eine echte punkt zu punkt verbindung würdest du zur zeit nur über ein eigenes socket bekommen. mit dem problem das manche browser nicht mehr als eine verbindung erlauben.

meine idee ist hier über das bestehende longpoll socket eine art subscribe and publish einzubauen so das nicht mehr jeder alle nachrichten bekommt. das FW_directNotify ist der erste schritt in diese richtung.

gefiltert wird zur zeit auf fhemweb seite auf device ebene. wenn ein device nicht im aktuell angezeigten raum ist (bzw. nicht im inform filter) werden die events gar nicht erst abgesendet.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Markus Bloch

1. und 3. ist schonmal geklärt. :)

zu 2.

Hast du hier genauere Informationen wie das mit setValueFn funktioniert? Man erstellt einen neuen Eintrag in der FW_widgets[] Liste (Bezeichnung scheint egal muss nur eindeutig sein) eine createFn in welcher man alle <table>-Tags mit class =  [Modulname] findet und als setValueFn einen eigenen Handler setzt, der sich dann um die Aktualisierung kümmert. Ist das richtig? Bin noch nicht sicher ob das so richtig ist, wo ich InformId's setzen muss und wie ich die SetValueFn richtig setze.

Danke

Gruß
Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

Markus Bloch

Ok, ich bin soweit, dass die Daten zu meinem eigenen Handler als setValueFn durchkommen, allerdings sind mir ein paar Merkwürdigkeiten aufgefallen.

Es müssen in der Event-Liste immer exakt 3 Elemente stehen. [ informId, Wert, nochmal der selbe Wert??? ]
Warum muss der Wert da 2 mal drinn stehen? Ich hätte jetzt folgendes Array gebaut und mit FW_directNotify ausgeführt: [ informId, JSON-Daten, 1]

Der Handler würde dann die JSON Daten auseinandernehmen und durch jQuery-Aufrufe an die richtigen Stellen in der Tabelle packen.

Finde ich etwas umständlich das man in der setValueFn nicht das gesamte Event-Array bekommt. Jetzt muss ich per jQuery mir erstmal mein zu bearbeitendes Objekt suchen.
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

justme1968

komme erst jetzt zum antworten. schön das es schon so weit geht.

das mit den exakt drei elementen ist noch dem ursprung aus dem normalen longpoll update geschuldet.

ich bin noch nicht dazu gekommen es bei mir einzubauen. deshalb ist es noch nicht auf eigenes protokoll und json optimiert.

wenn du deine objekte passend benennst bzw. ihnen passende id und/oder attribute gibst ist das suchen über einen selector und ein each ganz einfach.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Markus Bloch

nur mal so für dich zur Info.

hier mein Javascript Code in fhem_fbcalllist.js:

function FW_processCallListUpdate(data)
{
    log("list update: "+data);
}



function FW_FbCalllistCreate(elName, devName, vArr, currVal, set, params, cmd)
{
    if(vArr[0] == "fbcalllist")
    {
        var newEl = $('div[informId='+devName+']').get(0);

        newEl.setValueFn = FW_processCallListUpdate;

        return newEl;
    }
}

FW_widgets['fbcalllist'] = {
  createFn:FW_FbCalllistCreate
};


Und um meinen HTML-Output in der FW_detailFn/FW_summaryFn dann folgendes DIV-Tag:


$ret .= "<div class=\"fhemWidget\" informId=\"$name\" cmd=\"\" arg=\"fbcalllist\" dev=\"$name\">"; # div tag to support inform updates


Wenn ich nun in der FHEM-Kommandozeile ein:
{FW_directNotify("Anrufliste",'{"foo" : "baar"}',1)}
eingebe, kommt der entsprechende Log-Eintrag in der JS-Console.

Jetzt muss ich nur noch meinen Handler ausimplementieren. Auf das entsprechende <div>-Tag kann man über $(this) zugreifen. Dann sucht man sich die entsprechenden <tr>/<td>-Tags und setzt die entsprechenden Werte rein. Das ist aber kein Problem.

Vielen Dank für deine Unterstützung. Beim nächsten Usertreffen in Karlsruhe bin ich definitiv dabei. Hast ja schon einige Biere bei mir gut ;-)

Gruß
Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

justme1968

hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Markus Bloch

Hallo nochmal,

ich habe festgestellt, das es zu Problemen kommt, sobald man ein Modul, welches genau auf diese Weise eine Tabelle erzeugt, in eine Group packt. Da dann das umschließende <td> Tag, welches den HTML Output enthält ebenfalls eine informid=<devname> enthält und damit zuerst bei Events angesprochen wird und dann den 3. Wert aus dem Inform-Array setzt (da habe ich moment eine "1" stehen). Damit wird dann die gesamte Tabelle, die mein Modul erzeugt hat durch eine "1" ersetzt.

Um das zu verhindern, musste ich folgenden Javascript-Code ergänzen.


// remove all similar informid's in all parent elements to ensure further updates
$(function () {

    $("div[arg=fbcalllist][informid]").each(function (index, obj) {
       
        name = $(obj).attr("dev");
        $(obj).parents("[informid="+name+"]").removeAttr("informid");
    });
});


Ist zwar nicht die feine englische Art, aber funktioniert. Es gibt glaube ich keine Möglichkeit FHEMWEB zu sagen, dass man die informid's im HTML Output selber gesetzt hat und damit keine übergeordneten informid's benötigt, oder?

Gruß
Markus
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

justme1968

doch die gibt es. jedenfalls für die 'neue' methode in der der html für die widgets auf js seite erzeugt wird und nicht mehr auf fhemweb seite. das hatten wir eingebaut weil ich damals das gleiche problem hatte.


informid=<devname> ist eigentlich für state reserviert. vermutlich ist hier noch etwas nicht ganz konsistent. gibt es das problem auch wenn du ein normales device in eine group steckst? ich meine das es hier eigentlich richtig funktioniert.

du kannst aber die inform id die du für deine elemente verwendest doch frei wählen. d.h. du könntest für die komplette tabelle etwas anderes verwenden so das kein konflikt mehr entsteht.

gruss
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Markus Bloch

Bei bestehenden Geräten in Gruppen tritt das nicht auf. Das ist nur jetzt bei meinem neuen Modul, wo ich meine Tabelle selber im Modul erstelle und mit informid's versehe.

Ich werde es mal so probieren meinen InformId's noch ein Prefix vorzusetzen, damit es sich vom reinen Gerätenamen abhebt. Damit würde die übergeordnete informid von FHEMWEB im <td> Tag nicht mehr greifen.

Weis nicht, ob das so gedacht ist.
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

Markus Bloch

Sobald ich ein Präfix oder Postfix verwende, wird die Nachricht nicht mehr an den Client ausgeliefert.

Ich habe Probiert:

<devicename>-update
update-<devicename>

Wenn ich nur den reinen Devicenamen nehme, kommt es an, nur dann habe ich eben die Konflikte, sobald sich die Definition innerhalb einer Gruppe befindet.
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)

justme1968

der device name  muss passen weil sonst der inform filter auf sende seite zuschlägt da das device nicht im raum ist.

bei reading teil bist du völlig frei. z.b.

<device>.meineGanzeTabelle

gruß
  andre
hue, tradfri, alexa-fhem, homebridge-fhem, LightScene, readingsGroup, ...

https://github.com/sponsors/justme-1968

Markus Bloch

funktioniert leider auch nicht.

Ich setze in einem Fenster in der FHEMWEB Kommandozeile ein


{FW_directNotify("test.update","event1","event2")}

ab (test ist mein Device-Name)

kommt trotzdem nicht an. Wird meiner Meinung nach garnicht erst rausgesendet.
Developer für Module: YAMAHA_AVR, YAMAHA_BD, FB_CALLMONITOR, FB_CALLLIST, PRESENCE, Pushsafer, LGTV_IP12, version

aktives Mitglied des FHEM e.V. (Technik)