neues Modul '98_websocket.pm'

Begonnen von ntruchsess, 13 November 2014, 15:21:38

Vorheriges Thema - Nächstes Thema

ntruchsess

da nicht alle in der 'English Corner' mitlesen, hier mal ein Hinweis auf das websocket-modul, dass ich gerade in der Entwicklung habe

Da ich nicht weis, ob der ursprüngliche Anforderer das Thema noch weiter verfolgt (er hat die Lösung über mqtt erfolgreich anwenden können...), können wir das auch gerne hier (auf deutsch) weiterdiskutieren.

Das Feedback der Frontendentwickler wäre mir sehr wertvoll.

- Norbert
while (!asleep()) {sheep++};

herrmannj

Hallo Norbert,

sehr gern. Das es bzgl websockets eine weitere, bereits sehr weit fortgeschrittene, Implementierung für das smartVisu frontend gibt hast Du ja schon mit bekommen. Das ist in Bezug auf Überschneidung bzw evtl gedoppelter Funktionalität jedoch unbedenklich weil die Implementierung sehr genau auf das frontend zugeschnitten ist und Du ja den generischen Weg suchst.

Ich benutze übrigens Net::WebSocket::Server in einem geforkten Prozess.

Das nur zur Info, evtl sollten wir uns auf (unterschiedliche) Ports einigen.

vg
jörg

ntruchsess

#2
ich habe schon mitbekommen, dass Du da was speziell für SmatVisu realisiert hast, richtig greifbare Details habe ich aber nicht dazu gefunden (oder überlesen, Dein Thread is ja schon sehr lang geworden). Ich wollte das halt a) generisch und gut wiederverwendbar b) in fhem integriert haben (was in Bezug auf Performance und funktionell echte Vorteile hat). Soll u.a. geeignet sein Longpoll im FHEMWeb zu ersetzen.

Mit dem Port gibt's keine Probleme, der ist eh konfigurierbar (wie im telnet-modul).

den Net::WebSocket::Server habe ich natürlich auch angeschaut. Der ist halt nicht einbettbar, der braucht zwingend einen eigenen Prozess (oder Thread).

Ich hab nur kein richtiges Gefühl dafür, ob die (remote) API so sinnvoll/zu kompliziert/zu sehr 'fhem'/... ist. Also was sich ein Webentwickler so wünschen würde.
while (!asleep()) {sheep++};

herrmannj

#3
Mal direkt gefragt: kann man Deine Implementierung denn irgendwo herunterladen?

EDIT: äh wie jetzt, da habe ich wohl ausversehen Jörgs Beitrag überschrieben? Seit wann geht das denn? Sorry, das war echt keine Absicht
- Norbert

chris1284

#4
hi,

spiele seit deinem Post in dem englichen Thema mit dem Modul rum. Ein jsonlist2 lässt fhem abstürzen
ZitatPayload is too big. Send shorter messages or increase max_payload_size at /usr/local/share/perl/5.14.2/Protocol/WebSocket/Frame.pm line 250.
ersheint auf der shell

Ansonsten scheint es stabil zu funktionieren

herrmannj

Zitat von: herrmannj am 13 November 2014, 16:40:29
Mal direkt gefragt: kann man Deine Implementierung denn irgendwo herunterladen?

EDIT: äh wie jetzt, da habe ich wohl ausversehen Jörgs Beitrag überschrieben? Seit wann geht das denn? Sorry, das war echt keine Absicht
- Norbert
Ist das witzig  :) Fehler in der forumssoftware. Antwort auf deine Frage, ne noch nicht, weil noch nicht komplett. für die meisten user ist "90% Code ist drin" nix wert, da zählt geht oder geht nicht.

Ich stelle es dir gern, so wie es ist, zur Verfügung, der websocket Teil ist komplett funktionell und wenn wir synergien finden bin ich total dafür. Ich hänge das später an den Thread

Vg
Jörg

herrmannj

büddeschön.

01_smartVisu.pm enhält den server. Der wird über einen timer geforkt weil es über das define (warum auch immer) blockiert.
Entscheidung zum net::websocket::server getroffen weil stabiler. Kurzfristig geplant: zweiter fork mit tls und client zertifiken. Die Kommunikation zu parent läuft über tcp damit ich für die windows user auf pipes verzichte. Gleichzeitig vorbereitet um weitere forks loszulassen ohne auf das blocking.pm telnet angewiesen zu sein. Notwendig damit ich zb Video oder Audio über den ws ins frontend bringen kann. Daher komplexer.

vg
jörg

ntruchsess

Hallo Jörg, danke Dir. Wie läuft denn nun die smartVisu-seite? Hab mir das grade mal angesehen, da sind in directory 'driver' ja javascript-treiber zur Kommunikation mit verschiedenen Backends drin, wie fügt sich das da ein?
Was genau bearbeitet man denn mit dem smartVisuEditor?
while (!asleep()) {sheep++};

ntruchsess

Zitat von: chris1284 am 13 November 2014, 18:44:35
Payload is too big. Send shorter messages or increase max_payload_size at /usr/local/share/perl/5.14.2/Protocol/WebSocket/Frame.pm line 250.

Oh, guter Hinweis, meine Testinstanz war dafür einfach zu klein. Dann muss das konzeptionell anders gelöst werden, am besten indem man die ganzen Device-infos als Einzelmessages schickt und auf der Client-seite aggregiert. Da die Verbindung ja offen bleibt und die Reihenfolge garantiert ist, sollte da keine Probleme mit der Konsistenz oder so machen.

- Norbert
while (!asleep()) {sheep++};

ntruchsess

#9
um das Problem der limitierten Framesize zu umgehen habe ich das command 'list' umgeschrieben. Es sendet jetzt für jedes Device eine eigene message vom typ 'listenty'. Deren Inhalte sind voll durchstrukturiert, d.h. die erlaubten Attribute und Ihre Werte kommen jetzt in einem hash und nicht nur als Space/Doppelpunk/Komma-separierter String. Der Timestamp von readings wird auch als direkt in Javascript parsbarem GMT-Zeitformat übermittelt.

z.B.

{"type":"command","payload":{"command":"list","arg":"dummy"}}


->

{ "type":"listentry"
  "payload":{
    "name":"dummy",
    "arg":"dummy",
    "index":0,
    "num":1
    "internals":{
      "STATE":"on",
      "TYPE":"dummy",
      "NR":15,
      "NAME":"dummy"
    },
    "readings":{
      "state":{
        "time":"Fri Nov 14 08:58:26 2014 GMT",
        "value":"hallo_welt: on"
      }
    },
    "attributes":{
      "room":"raum"
    },
    "sets":{},
    "gets":{},
    "attrList":{
      "event-on-update-reading":null,
      "setList":null,
      "comment":null,
      "widgetOverride":null,
      "event-on-change-reading":null,
      "group":null,
      "room":null,
      "icon":null,
      "verbose":["0","1","2","3","4","5"],
      "event-min-interval":null,
      "devStateStyle":null,
      "stateFormat":null,
      "alias":null,
      "eventMap":null,
      "userattr":null,
      "sortby":null,
      "webCmd":null,
      "devStateIcon":null,
      "userReadings":null
    },
  },
}
while (!asleep()) {sheep++};

ntruchsess

#10
hab eine kleine javascript-library dazu geschrieben und das html-beispiel darauf umgestellt:


<!DOCTYPE html>
<html lang="de">
<head>
<title>fhem websocket test</title>
<script src="./fhem.js" type="text/javascript"></script>
<script type="text/javascript">

var fhem = new fhem();

fhem.ondebug = function(m) {
  document.getElementById("debug").value = m;
}

fhem.onerror = function(m) {
  document.getElementById("error").value = m;
}

fhem.onconnected = function() {
  fhem.subscribeAll();
  fhem.sendCommand({
    command: 'list',
    arg:     '.*'
  });
}

fhem.onevent = function() {
  document.getElementById("fhem").value = JSON.stringify(fhem.devices);
}


fhem.onlist = function() {
  document.getElementById("fhem").value = JSON.stringify(fhem.devices);
}

openCon = function() {
  fhem.connect('localhost','8080');
}

closeCon = function() {
  fhem.disconnect();
}

sendCommand = function() {
var input = document.getElementById("input").value;
  fhem.sendCommand({
    command: input
  });
}

</script>
</head>
<body>

<p><input type="button" value="open" onclick="openCon();"/></p>
<p><input type="button" value="close" onclick="closeCon();"/></p>
<p><input id="input" type="text"/><input type="button" value="senden" onclick="sendCommand();"/></p>
<p>debug: <output id="debug" type="text"/></p>
<p>error: <output id="error" type="text"/></p>
<p>fhem: <output id="fhem" type="text"/></p>

</body>
</html>


Die Seite erlaubt zum fhem per websocket zu verbinden und man kann fhem-befehle absetzen. Unten wird der Aktuelle Stand aller Devices im JSON-format dargestellt - Änderungen (z.B per 'set xxx yyy') werden da von der Serverseite direkt reingepusht :-)

fhem.js,
websocket.html
98_websocket.pm

EDIT: object-orientiertes refactoring der fhem.js committed...
while (!asleep()) {sheep++};