fhem.js - websocket connection to fhem via node.js proxy

Begonnen von Werner Schäffer, 13 Februar 2015, 21:53:55

Vorheriges Thema - Nächstes Thema

Werner Schäffer

Zitat von: rretsiem am 24 April 2015, 17:54:06
Ich hatte mir die Server.js schon angesehen wie du das normale list implementiert hattest aber hatte auch noch keinen Zeit da was zu tun.
Ich denke aber auch das das spezielle Commando besser in beim Server aufgehoben ist, dann kann der das parsen und aufbereiten und nur noch das Json zurückschicken. Wenn ich das via command baue dann muss der Client ja alles tun?

bingo!

HansDampfHH

So, da bin ich leider noch einmal ;-)
Das mit export.PathHTML und dem root war mir nicht klar.

exports.pathHTML = '/var/www/fhem.js';
exports.indexHTML = 'index.html';

Nach Aufrufen von http://192.168.178.30:8086/index.html lädt die Seite und mit dem Call getAllValues bekomme ich den repsonse.
Was noch nicht funktioniert ist die Möglichkeit mit getAllValuesOnChange. Da kommt in der index.html nichts an (Console, Netzwerk).

Im Terminal sieht es wie folgt aus:


25.04.2015 08:25:26 listen for http requests
25.04.2015 08:25:26 Server started: without SSL
25.04.2015 08:25:26 initFinished
25.04.2015 08:25:26 start connection to fhem server
25.04.2015 08:25:26 connected to fhem server for listen on changed values
25.04.2015 08:25:29 emit authenticated
25.04.2015 08:25:29 client connected
25.04.2015 08:32:10 disconnected: transport close
25.04.2015 08:32:57 http request: /index.html
25.04.2015 08:32:58 emit authenticated
25.04.2015 08:32:58 client connected
25.04.2015 08:32:58 request for getAllValuesOnChange
FHEM Docker, CUL868, Zigbee, CCU2, Jeelink

rretsiem

Zeige doch mal bitte wie du den GetAllValuesOnChange am Client implementiert hast.

Außerdem hilft mir bei solchen Problemen immer die JavaScript Konsole und der Debugger in Safari oder Chrome. Da kannst du einfach einen Breakpoint setzen und die Rückgabewerte in der Konsole einzeln betrachten.

rretsiem


Zitat von: Werner Schäffer am 24 April 2015, 18:41:58
bingo!

Ich war mal so frei und habe gestern Abend einen Fork erstellt und entwickle was in die Richtung.
Das Json habe ich schon, aber noch Probleme die einzelnen Objekte anzusprechen am Server. Irgendwie die das JS Objekt nach JSON.parse(JSON.stringify(...)) zwar o.k aus. Aber mit Object.Key erhalte ich lediglich ein Objekt mit length == 2.

Eigentlich sollte da aber deutlich mehr drin stehen.
Hast du einen Tipp wie ich das am besten debuggen kann Au Node.js Seite. Oder hilft nur alles loggen und Trial&Error?

HansDampfHH

Der springt gar nicht in die Routine, im Debugger tut sich also nichts.

Zitat
<script>
   var socket = io.connect('http://192.168.178.30:8086');
   socket.emit('getAllValuesOnChange', function(data){
      alert(data);
      var out = '';
      for (unit in data){
         var value = data[unit];
         out += unit + ': ' + value + "<br>";
      }
      $("#container").html(out);
   });
</script>
FHEM Docker, CUL868, Zigbee, CCU2, Jeelink

Werner Schäffer

Zitat von: HansDampfHH am 25 April 2015, 11:38:42
Der springt gar nicht in die Routine, im Debugger tut sich also nichts.

getAllValuesOnChange ist ein Async-Request

Also:

socket.emit('getAllValuesOnChange');

socket.on('value',function(data)
{
...
});


Werner Schäffer

Zitat von: rretsiem am 25 April 2015, 11:28:08
...
Hast du einen Tipp wie ich das am besten debuggen kann Au Node.js Seite. Oder hilft nur alles loggen und Trial&Error?

Es gibt den node-inspector (npm install -g node-inspector). Damit kann man mit Chrome auf einem Client einen node.js Server debuggen. Ich bin aber nicht richtig warm damit geworden, weil das Ganze ziemlich träge ist und es dann auch nicht so funktioniert hat wie ich erwartet hatte.

HansDampfHH

*grrr* Danke !
Das war es, nun läuft es genau so wie ich es brauchen kann.
Perfekt. Ich danke Dir für Deinen Support. Super Sache :-)
FHEM Docker, CUL868, Zigbee, CCU2, Jeelink

Werner Schäffer

Ich habe gerade eine neue Version auf Github geladen.

Es gibt jetzt den request 'JsonList2'.
(@rretsiem: der Response von JsonList2 ist so groß dass er durch fhemcmd in mehrere Pakete aufgeteilt wird, die man wieder zusammensetzen muss. Zu beachten auch dass beim call 'JsonList2' ein ';exit' angehängt wurde. Damit wird der event 'end' ausgelöst und man weiß dass alle Datenpakete geliefert wurden. Diesen Mechanismus musste ich auch noch bei 'command' einbauen.)

Außerdem steht jetzt im Verzeichnis test ein ausführlicheres Beispiel und in dem Verzeichnis /etc/init.d steht ein Script mit fhem.js mit Hilfe von forever als Service ausgeführt werden kann.

rretsiem

#39
Klasse Arbeit. Danke, hatte mir wie gesagt das Result noch nicht anschauen können. Hätte ich heute Abend gemacht.
Dann schaue ich mir mal deine Implementierung an.
Da ungesehen, mein Ansatz war das ich getAllValues usw. ersetze durch den JSON request, weil sich da Node einfach zu Hause fühlt. Im Gegensatz zum geparse der Liste und regex durch einzelne Zeilen. Damit könnte man doch 2 Fliegen mit einer Klappe schlagen. Die normalen "list " requests wären dann überflüssig. Oder vergesse ich irgendwas dabei?

Nachtrag: bist du offen für Pullrequests wenn sie sinnvoll sind? Habe zwar mit Github erst wenig gemacht (keine Forks) aber vielleicht bietet sich ja die Gelegenheit an, deine Lösung ist nämlich ein sooooo viel besserer Ansatz als diese doofen und fehleranfälligen Longpolls :-)

Werner Schäffer

Zitat von: rretsiem am 25 April 2015, 17:48:40
...

Nachtrag: bist du offen für Pullrequests wenn sie sinnvoll sind? Habe zwar mit Github erst wenig gemacht (keine Forks) aber vielleicht bietet sich ja die Gelegenheit an, deine Lösung ist nämlich ein sooooo viel besserer Ansatz als diese doofen und fehleranfälligen Longpolls :-)

Gerne!

Das bisherige Paket ist ja auch noch verbesserungsfähig, da ich das erst mal ganz gezielt entwickelt habe um ein Android Widget zu programmieren. Es sind deshalb auch einige Elemente darin die speziell auf meine Anforderungen zugeschnitten sind. Eine Verallgemeinerung der Schnittstellen kann nie schaden.

Anderseits ist natürlich dieser fhem.js Server ein zusätzlicher Aufwand. Die bessere Lösung wäre Websocket-Funktionalität, als Ersatz für longpoll, direkt in fhem.pl zu implimentieren. Es gab da auch wohl schon Ansätze, aber die sind irgendwie wieder eingeschlafen. Deshalb habe ich diesen fhem.js entwickelt.

rretsiem

Zitat von: Werner Schäffer am 25 April 2015, 18:04:58
Gerne!

Das bisherige Paket ist ja auch noch verbesserungsfähig, da ich das erst mal ganz gezielt entwickelt habe um ein Android Widget zu programmieren. Es sind deshalb auch einige Elemente darin die speziell auf meine Anforderungen zugeschnitten sind. Eine Verallgemeinerung der Schnittstellen kann nie schaden.

Ich habe mal etwas gebastelt und herausgekommen ist eine eigenen Branch...  :o https://github.com/rretsiem/fhem.js/tree/bufferJSON

Schaue dir das mal an und sage mal was du davon hältst.

TL;DR:
Ich habe die Verarbeitung auf Jsonlist2 umgestellt, soweit möglich, das telnet "inform on" ist weiterhin kein JSON, allerdings resultiert ein update eines Devices aus "inform on" auch wieder in einem Jsonlist2 request für das entsprechende Device.

Der Vorteil den ich im Moment sehe ist das man beliebige Readings und States zur Verfügung hat und zwar bereits als JSON. Ich habe allerdings im moment die "Internals" usw. nicht mit im buffer.aktValues.

Der Nachteil, es bricht denke ich im Moment(!!) die Kompatibilität mit deiner Version, da deutlich mehr Informationen über die Leitung gehen. Aber dem kann man ja mit entsprechenden Funktionen die dann auch wieder nur die States liefern (falls man nicht mehr benötigt) entgegenwirken. Siehe dazu die getStates() Funktion die via .emit() auch ein 'all' oder beliebiges Device zurückliefert.

Ich habe das mal absichtlich in eine eigene Branch gepackt (Musste ich erstmal lernen und lesen wie das funktioniert :) )
Wenn du damit überhaupt nix anfangen kannst, bin ich trotzdem offen für eine Diskussion! Das ist nur ein Vorschlag!

Werner Schäffer

Ich kann das so nicht akzeptieren. Drei Gründe:

1. wie du schon sagst es nicht mehr kompatibel mit meiner bisherigen Lösung. Ich habe schon eine umfangreiche Java-Anwendung für ein Android Widget programmiert, die node.js so benötigt wie ich es erstellt habe.

2. das Hauptmerkmal von node.js soll sein dass der Client bestimmt welche Daten er braucht und er diese, und nur diese, bei Änderung automatisch über eine Websocket Verbindung erhält. Dies soll gewährleisten dass bei einem Smartphone das mobil im Netz ist nicht die permanente Datenflut von fhem-Werten das Datenkontigent zu stark in Anspruch nimmt. Man muss bedenken dass ein Widget immer aktiv ist sobald das Gerät eingeschaltet ist. Wenn man z.B. 10 Heizkörberthermostate hat, bei denen eigentlich nur die gemessene Temperatur interessiert, dann werden wenn man da die Json_Struktur verschickt zu schätzungsweise 95% unnötige Daten mitübertragen.

3. die Lösung mit inform on und dann bei Änderung einen JsonList2 auf die Device abschicken gefällt mir überhaupt nicht, da die eigentliche Information durch inform ja schon geliefert wird. Diese Lösung ist Programmierfaulheit auf Kosten der Performance. Man sollte bedenken das fhem und dann auch fhem.js oft auf einem Raspi installiert sind und dort hat man nun mal keinen 8-Kern Prozessor mit 3,2Ghz. Bei dieser Lösung vermute ich dass Statusänderungen deutlich länger brauchen bis sie beim Client ankommen, da man die Zeit für den Aufbau einer telnet-Verbindung, die ja bei jeder Änderung anfällt, nicht unterschätzen darf.

Als Lösung denke ich dass man die JsonList aller Measerments im Buffer halten muss und Änderungen die man per inform erhält müssen in den Buffer geschrieben und falls von einem Client abonniert an diesen geschickt werden.

Am Besten ist wohl wenn du deinen eigenen Branch pflegst und ich meinen. Schon wegen 1. bin ich da nicht kompromissbereit und wegen 2. eigentlich auch nicht. Wir können uns aber gerne weiter austauschen.


rretsiem

Zitat von: Werner Schäffer am 28 April 2015, 12:58:46
Ich kann das so nicht akzeptieren. Drei Gründe:

1. wie du schon sagst es nicht mehr kompatibel mit meiner bisherigen Lösung. Ich habe schon eine umfangreiche Java-Anwendung für ein Android Widget programmiert, die node.js so benötigt wie ich es erstellt habe.
Das hatte ich ja auch geschrieben und daher als Beispiel einen neuen listener (getStates) implementiert der wie bisher bei deiner Lösung nur die States zurückliefert. Hier könnte man sicherlich noch weiter ansetzen so das deine Implementierung nicht gefährdet wird und man lediglich neue Listener einführt die dann nicht nur die States, sondern auch die Readings beinhalten. Soll heißen die bisher verwendeten Listener von dir werden so geändert das sie aus dem JSON Buffer wieder die exakt gleichen Werte liefern wie bisher.

Zitat
2. das Hauptmerkmal von node.js soll sein dass der Client bestimmt welche Daten er braucht und er diese, und nur diese, bei Änderung automatisch über eine Websocket Verbindung erhält. Dies soll gewährleisten dass bei einem Smartphone das mobil im Netz ist nicht die permanente Datenflut von fhem-Werten das Datenkontigent zu stark in Anspruch nimmt. Man muss bedenken dass ein Widget immer aktiv ist sobald das Gerät eingeschaltet ist. Wenn man z.B. 10 Heizkörberthermostate hat, bei denen eigentlich nur die gemessene Temperatur interessiert, dann werden wenn man da die Json_Struktur verschickt zu schätzungsweise 95% unnötige Daten mitübertragen.
Sehe ich genau so, siehe oben, noch ist das ein erster Wurf und durch entsprechende Listener könnte man das umgehen, bzw. zusätzliche Informationen erhalten die eben jetzt nicht vorhanden sind.
Ich habe das mal mit meinen Homematic-Thermostaten durchgespielt, wenn man lediglich die States braucht, klar, aber was wenn man auch den controlMode/controlManu/partyMode auslesen möchte, das liefert der State ja leider nicht.

Zitat
3. die Lösung mit inform on und dann bei Änderung einen JsonList2 auf die Device abschicken gefällt mir überhaupt nicht, da die eigentliche Information durch inform ja schon geliefert wird. Diese Lösung ist Programmierfaulheit auf Kosten der Performance. Man sollte bedenken das fhem und dann auch fhem.js oft auf einem Raspi installiert sind und dort hat man nun mal keinen 8-Kern Prozessor mit 3,2Ghz. Bei dieser Lösung vermute ich dass Statusänderungen deutlich länger brauchen bis sie beim Client ankommen, da man die Zeit für den Aufbau einer telnet-Verbindung, die ja bei jeder Änderung anfällt, nicht unterschätzen darf.

Harsche Worte :-[ Zumindest das Thema "Faulheit", denn genau das habe ich damit überhaupt nicht vor. Ich fand nur den Ansatz eine Telnet-Session zu loggen und dann die Zeilen einzeln zu parsen und zu hoffen das alles enthalten, dann wieder als JSON zu parsen ist deutlich komplexer als beim ersten Anzeichen einer Device-Änderung lokal via Telnet mit Jsonlist2 den entsprechenden Status zu parsen deutlich eleganter. Zusätzlich dazu hält man pro Device somit auch immer den wirklichen aktuellen Status im "buffer" und nicht nur den geänderten.

Ich entwickle das auf einen RasPi... Kann aber natürlich zur Performance dazu wenig sagen. Soweit ich deinen Code richtig interpretiere machst du beim "Fund" von einer foundSingleEntity in CheckValues() jedes Mal einen "list" via Telnet und parsed die komplette Device-Struktur wieder. Ich denke nicht das dies so ein großer Unterschied ist zur Jsonlist2 Lösung auf Device Ebene?

Zitat
Als Lösung denke ich dass man die JsonList aller Measerments im Buffer halten muss und Änderungen die man per inform erhält müssen in den Buffer geschrieben und falls von einem Client abonniert an diesen geschickt werden.
Das war mein erster Ansatz, bin dann aber wegen des parsens der "inform on" Werte wieder davon abgekommen, weil der inform on keine sauberen Werte zurückliefert die man "einfach" in ein JSON Object wandeln kann und damit im Buffer aktualisieren kann.

Zitat
Am Besten ist wohl wenn du deinen eigenen Branch pflegst und ich meinen. Schon wegen 1. bin ich da nicht kompromissbereit und wegen 2. eigentlich auch nicht. Wir können uns aber gerne weiter austauschen.
Das wollte ich eben vermeiden, allerdings bin ich davon ausgegangen das du auch Kompromisse eingehst, zumindest wenn ich deine Aussage von vor wenigen Tagen richtig interpretiere: http://forum.fhem.de/index.php/topic,33755.msg289217.html#msg289217

Werner Schäffer

Ja meine Aussage vor ein paar Tagen war etwas anderst, da hatte ich aber nicht richtig darüber nachgedacht, aber ich kann keine Kompromisse eingehen weil ich die Funktionalität genau so brauche wie sie jetzt ist, auch was die Nomenklatur betrifft. Außerdem bin ich nachwievor der Ansicht dass dies nur eine Hilfslösung ist und das eigentliche Ziel sein sollte die Websocket-Funktionalität direkt in fhem.pl einzubauen.

Außerdem ist mir die Abfolge "inform on -> get change -> open telnet -> JsonList2 device ->wait for response -> emit JsonList an client" einfach nicht sympatisch und widerspricht meinen Vorstellungen.