WebSocket via DevIO?

Begonnen von KernSani, 06 April 2020, 07:43:45

Vorheriges Thema - Nächstes Thema

KölnSolar

Danke Rudi. Ich probier es mal aus.

Trotzdem würde ich gerne verstehen(zu meiner Weiterbildung  ;D), warum das bei mir nicht klappte.
Zitatauf Basis des in den Kommentaren verlinkten Artikels
Genau den suche ich immer wieder vergebens. Ich weiß, dass ich einen Link irgendwo gesehen hatte....Weißt Du noch wo bzw. wie der lautet ?

ZitatBei mir klappt das... Auch wenn die Lösung äußerst unschön ist. Eigentlich sollte das eine globale Variable o.ä. sein.
Wenn ich aber ein list device mache, gibt es bei mir keine helper-Variable. Bei Dir ?!?!?!?! Oder "versteckt" list den Eintrag u. führt mich in die Irre ?

RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

RichardCZ

Perltidy krächzt.

419: return $doCb("websocket is only supported with callback") if(!$c ...
            -----^
found ( where operator expected (previous token underlined)

Do you mean '$doCb->(' ?
Witty House Infrastructure Processor (WHIP) is a modern and
comprehensive full-stack smart home framework for the 21st century.

rudolfkoenig

Danke fuer den Hinweis, habs gefixt.

KernSani

Hallo Rudi,

danke für den Einbau. Leider scheitere ich in meinem Anwendungsfall schon beim Verbindungsaufbau. Der Websocket-Server ist in meinem Fall erreichbar unter einer URL der Form wss://host:port/irgendwas?undmehr=1&bla. Devio reduziert leider erstmal auf host:port (das passt ja auch für den tcpsocket) und hängt dann ein http/https für den nonBlocking-Connect vorne dran, dadurch ergibt sich https://host:port und die Websocketverbindung kommt natürlich nicht zu Stande.
Meine aktuelle Implementierung (auch vor Anpassung von DevIo) läuft vereinfacht gesagt wie folgt:
* DevIo baut tscpsocket auf (host:port)
* Basierend auf tcpsocket ($hash->{TCPDev}) wird Protocol::WebSocket::Client instantiiert (mit kompletter URL)
* Protocol::WebSocket::Client macht Handshake (upgrade etc...)
* ReadFn leitet $buf an Protocol::WebSocket::Client weiter, um Rückgabe zu bearbeiten.

Welchen Input benötigst du um das auf DevIO-Seite zu optimieren?

Danke,

Oli

RasPi: RFXTRX, HM, zigbee2mqtt, mySensors, JeeLink, miLight, squeezbox, Alexa, Siri, ...

rudolfkoenig

Meines Wissens sollte das Beschriebene ohne "Optimierung" funktionieren.
wss:XX ist als ws:XX + $hash->{SSL}=1 zu spezifizieren, analog zu TCP, siehe mein Beispiel.

KölnSolar

Hi Rudi,
auch ich habe mich mühevoll versucht. Die Definition ist ja eigentlich einfach. Ich dachte, dass es an TLS liegt, aber scheinbar ist es etwas anderes beim handshake, das die Verbindung nicht zustande kommen lässt. Mit wscat u. der Test-Website, die Jörg genannt hatte, funktioniert alles bestens.

Ich hab nun die Möglichkeit das Ganze ohne TLS auszuprobieren. Ich guck mir das im Laufe des Tages mit tcpdump/Wireshark mal an.

Wunsch: Den opcode des frames zurückliefern. Insbesondere beim Test fänd ich es hilfreich, wenn die Info ankommt, dass der Server die Verbindung "geclosed" hat. Ich guck aber selber mal, ob man das einfach in DevIo unterbringen kann.

Grüße Markus
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

KölnSolar

#51
Lt. Wireshark antwortet der Server auf den upgrade websocket request
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: t4n9guUpD/ZNPtfze+r3aUVqTo0=
Date: Mon, 01 Jun 2020 07:32:51 GMT
Server: Python/3.5 websockets/7.0


dann noch ein TCP-Ack des FHEM-Servers an den websocket-Server, aber dann wartet FHEM den timeout(3s) ab.... :'(

Und so sieht das im FHEM-Log aus
2020.06.01 09:32:51 3: [EE2] sol_local EE2_Ready(connection seems to be lost) retrying wsconnect for DeviceName: ws:xxxip.de:9124
2020.06.01 09:32:51 5: HttpUtils url=http://xxxip.de:9124/
2020.06.01 09:32:51 4: IP: xxxip.de -> Ipdeshosts
2020.06.01 09:32:51 5: HttpUtils request header:
GET / HTTP/1.1
Host: xxxip.de:9124
User-Agent: fhem
Accept-Encoding: gzip,deflate
Sec-WebSocket-Key: sXh1fxWrbbVHEyfLPyO77Q==
Connection: Upgrade
Sec-WebSocket-Version: 13
Upgrade: websocket

2020.06.01 09:32:54 4: [EE2] sol_local - error while connecting to Websocket: read from http://xxxip.de:9124 timed out from DevIO
2020.06.01 09:32:54 4: [EE2] sol_local - callback called


Auf was wartet httputils bzw. DevIo da noch ?!?!?!?

Wenn Du mehr brauchst, melde Dich gerne
Grüße Markus

Correction: additional new line added
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

rudolfkoenig

ZitatAuf was wartet httputils bzw. DevIo da noch ?!?!?!?
Falls Du die Daten vollstaendig kopiert hast: auf einem zweiten NL nach dem Header.
Ich fuerchte mit dieser Methode kommen wir nur muehsam weiter: gibt es eine Moeglichkeit, dass ich mich direkt mit deinem Server verbinde?

Ich habe DevIo.pm erweitert: mit verbose 5 wird jedes websocket Frame geloggt, und wss: ist equivalent zu ws: + $hash->{SSL}=1;

KölnSolar

#53
Mit TLS kannst Du es auf sol.eet.energy:9124 testen.

Was ist ein NL ?  :-[

Danke fürs logging. Ich hol mir mal die aktuelle Version...

Allerdings genügt das Logging vermutlich nicht  :'( Ich konnte verfolgen, dass der Server alle 20s einen ping sendet, womit dann mit einem pong geantwortet wird(ansonsten schließt der Server die websocket-Verbindung). Ein websocket-frame ohne Daten kommt aber nicht im Modul über die ReadFn an, oder ? Oder ist das etwas, was in DevIo rein müsste ?
Ich glaube im konkreten Fall kommt kein Ping mehr, wenn man die ersten Daten(Logindaten)) geschickt hat...

Für ein anderes Modul überlege ich mir, ob ich auch auf DevIo umbaue. Allerdings ist das ein device, das nicht regelmäßig verfügbar ist. Du schreibst ja hier u. da, dass DevIo dann eher keinen Sinn macht. Was hältst Du von einer Lösung, wo die Verfügbarkeit des devices mit einem anderen Mechanismus überwacht wird und nur für die Dauer der Verfügbarkeit eine websocket-Verbindung aufgebaut bleibt, also Aufbau, wenn verfügbar und ein close(und damit auch kein ReadyFn/ReadFn ), wenn nicht mehr verfügbar.

Grüße Markus
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

rudolfkoenig

ZitatMit TLS kannst Du es auf sol.eet.energy:9124 testen.
Habs gemacht.
Eine websocket Verbindung wird zwar hergestellt, aber von der anderen Seite sofort geschlossen (mit OP:8 == Close), vermutlich weil das von mir gesendete "list" ohne Weiteres dem Server nicht passt.

NL steht fuer NewLine: ein HTTP Header wird mit zwei Newlines abgeschlossen, und in deinem Beitrag sieht man nur eins.
Ein Websocket Frame wird mit DevIO nie beim Modul ankommen, da das Prinzip von DevIo ist, vom Transportschicht-Eigenheiten zu abstrahieren.
Abgesehen davon wuesste ich nicht, warum Ping/etc das Modul interessieren sollte.

ZitatDu schreibst ja hier u. da, dass DevIo dann eher keinen Sinn macht.
Das ist vermutlich falsch interpretiert, kannst Du mir diesen Zitat zeigen?
Websocket ist (im Gegensatz zu HTTP) fuer eine laenger geoeffnete Verbindung ausgelegt.
Man kann es (wie alles) missbrauchen, und ob man das mit DevIo oder ohne macht, ist mir egal.

Zitat
Was hältst Du von einer Lösung, wo die Verfügbarkeit des devices mit einem anderen Mechanismus überwacht wird und nur für die Dauer der Verfügbarkeit eine websocket-Verbindung aufgebaut bleibt,
Wenig, wenn beide Verfahren das gleiche Medium (Netzwerk) nutzen.
Wenn die andere Seite nicht da ist, dann kriegt man das auch per websocket mit: ob jetzt ping oder der TCP Connect-Versuch keine Antwort kriegt, ist  egal. Es kommt dazu, dass man fuer ping entweder spezielle Rechte (root), oder unangemessen viel Ressourcen (fork+exec) braucht.
Heisst nicht, dass ich die, die sowas programmieren, aktiv verfolge, ich aussere nur meine Meinung, wenn ich danach gefragt werde :)

KölnSolar

#55
Hi Rudi,
ZitatEine websocket Verbindung wird zwar hergestellt, aber von der anderen Seite sofort geschlossen (mit OP:8 == Close), vermutlich weil das von mir gesendete "list" ohne Weiteres dem Server nicht passt.
Ja, das macht er, wenn ihm was nicht passt.  ;) Wie hast Du das denn jetzt mit dem "fehlenden" 2. NL gelöst ? Geänderte  DevIo sehe ich nicht.  :-[

ZitatAbgesehen davon wuesste ich nicht, warum Ping/etc das Modul interessieren sollte.
Das sehe ich dann, wenn es mal mit dem Modul klappt.... ;)
ZitatDas ist vermutlich falsch interpretiert, kannst Du mir diesen Zitat zeigen?
Finde ich bestimmt nicht mehr, aber Du hast ja jetzt ausführlich aufgeklärt.

Danke&Grüße Markus
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

KölnSolar

#56
Hm,
mein lokales device gibt auch nur ein NL zurück.  Das war wohl Quatsch. Du meintest ja die response. :( Trotzdem selbes Problem mit meinem lokalen device.

2020.06.01 13:50:57 5: HttpUtils url=https://localIP:8002/
2020.06.01 13:50:57 4: IP: localIP -> localIP
2020.06.01 13:50:57 5: HttpUtils request header:
GET / HTTP/1.1
Host: localIP:8002
User-Agent: fhem
Accept-Encoding: gzip,deflate
Sec-WebSocket-Key: 9nXYHmyxKMPCKREAHTn2Ng==
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Version: 13

2020.06.01 13:51:00 5: [SamsungAV] Fernseher - callback after connecting to Websocket by DevIO
2020.06.01 13:51:00 2: [SamsungAV] Fernseher - error while connecting to Websocket: read from https://localIP:8002 timed out from DevIO


Edit: Das mit dem NL ist es wohl nicht. Hab nochmal in Wireshark geguckt. Die response endet mit \r\n\r\n. Ich passdie obigen Posts mal an.
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

rudolfkoenig

Zitatmein lokales device gibt auch nur ein NL zurück.
Du verwirrst mich.
Im Code-Stueck sind zwei zu sehen: einmal nach "Sec-WebSocket-Version: 13" und danach die leere Zeile.
Der Zugriff auf "sol.eet.energy:9124" klappte ohne Aenderung, der schickt schon 2 NLs.

KölnSolar

#58
Ich mich auch. Hab jetzt erst gemerkt, dass Du ja die response meintest. Ja, da kommt die 2. NL. Hatte ich nur nicht mitkopiert. :o

Aber dann sind wir so weit wie heute Morgen: Was führt zu dem timeout ? Und viel schlimmer: wieso klappt das bei Dir ? ??? Da kann man doch eigentlich nichts falsch machen.  :-[

    $hash->{DeviceName} = "ws:".$hash->{Host} . ":" . $hash->{Port}; 
#    $hash->{SSL}         = 1;  # TLS only used for remote access; set by attribute   
#    $hash->{WEBSOCKET}   = 1;  set by Dev
    DevIo_OpenDev( $hash, 0, "wsHandshake", "wsCb" );

sub wsCb ($){
    my ($hash, $error)  = @_;

    my $name  = $hash->{NAME};

    if (defined($error)) {Log3 $name, 4, "[EE2] $name - error while connecting to Websocket: $error from DevIO" };
    Log3 $name, 4, "[EE2] $name - callback called";
    return $error;
}
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt

KölnSolar

Hi Rudi,
nachdem es also nicht am NL liegt, wird für mich die Sache immer ominöser. Was mich in meinem Log so blind gemacht hatte ist, dass es überflutet wurde. Das liegt daran, dass permanent die ReadyFN aufgerufen und ein Neuaufbau versucht wird. Es ist doch richtig, dass die ReadyFn eigentlich gar nicht aufgerufen werden dürfte oder zumindest der STATE auf connected stehen müsste, oder ?

Außerdem hadere ich mit dem reopen-Flag. Ich hab jetzt noch einmal ein wenig umgebaut und bekomme folgendes Logging
2020.06.01 23:17:38 3: [EE2] sol_local defined with host: localDomain port: 9124
...Versatz von 20s ist korrekt, weil der Aufbau über einen internaltimmer 20s nach dem define gestartet wird
2020.06.01 23:17:58 4: [EE2] sol_local  Attempting to open websocket by DevIo
2020.06.01 23:17:58 3: Opening sol_local device ws:localDomain:9124
2020.06.01 23:17:58 5: HttpUtils url=http://localDomain:9124/
2020.06.01 23:17:58 4: IP: localDomain -> localIP
2020.06.01 23:17:58 5: HttpUtils request header:
GET / HTTP/1.1
Host: localDomain:9124
User-Agent: fhem
Accept-Encoding: gzip,deflate
Upgrade: websocket
Sec-WebSocket-Version: 13
Connection: Upgrade
Sec-WebSocket-Key: 7i8DGRzM9v3nc2QrBABKIw==

2020.06.01 23:18:01 1: sol_local: Can't connect to localDomain:9124: No such file or directory
2020.06.01 23:18:01 1: sol_local: Can't connect to localDomain:9124: read from http://localDomain:9124 timed out
2020.06.01 23:18:01 4: [EE2] sol_local - error while connecting to Websocket: read from http://localDomain:9124 timed out from DevIO
2020.06.01 23:18:01 3: [EE2] sol_local EE2_Ready(connection seems to be lost) retrying wsconnect for DeviceName: ws:localDomain:9124
2020.06.01 23:18:01 3: Opening sol_local device ws:localDomain:9124
2020.06.01 23:18:01 4: [EE2] sol_local - connecting to Websocket successful
2020.06.01 23:18:01 3: [EE2] sol_local EE2_Ready(connection seems to be lost) retrying wsconnect for DeviceName: ws:localDomain:9124
2020.06.01 23:18:01 4: [EE2] sol_local - connecting to Websocket successful
2020.06.01 23:18:02 3: [EE2] sol_local EE2_Ready(connection seems to be lost) retrying wsconnect for DeviceName: ws:localDomain:9124
2020.06.01 23:18:02 4: [EE2] sol_local - connecting to Websocket successful
.
.
.
bei diesem coding.
.
Initial-websocket-connect
    $hash->{helper}{wsconnect} = 0;
    Log3 $name, 4, "[EE2] $name  Attempting to open websocket by DevIo";
    $hash->{DeviceName} = "ws:".$hash->{Host} . ":" . $hash->{Port}; 
    DevIo_OpenDev( $hash, 0, "wsHandshake", "wsCb" );
.
.
ReadyFN
   Log3 $hash->{NAME}, 3, "[EE2] $hash->{NAME} EE2_Ready(connection seems to be lost) retrying wsconnect for DeviceName: $hash->{DeviceName}";
  return DevIo_OpenDev( $hash, $hash->{helper}{wsconnect}, "wsHandshake", "wsCb" )
                if($hash->{STATE} eq "disconnected");     

wsCb
    if (defined($error)) {Log3 $name, 4, "[EE2] $name - error while connecting to Websocket: $error from DevIO" }
    else {
       Log3 $name, 4, "[EE2] $name - connecting to Websocket successful";
       $hash->{helper}{wsconnect} = 1;
    }

Auf ein write habe ich komplett verzichtet, da ggfs. der Server mit einem disconnect reagiert.

Aber wieso gibt es erst diese "Can't connect" Meldung mit 3s timeout, dann der identische Aufruf von DevIo(reopen=1), der nun scheinbar erfolgreich ist, aber nicht zu einem "connected" führt bzw. die ReadyFn aufgerufen wird, wo dann erneut ein erfolgreicher ws-connect(reopen=1) erfolgt, der aber wieder in die ReadyFN läuft. Und das dann permanent.

Soll ich das nochmal genau mit Wireshark analysieren ?

Grüße Markus
RPi3/2 buster/stretch-SamsungAV_E/N-RFXTRX-IT-RSL-NC5462-Oregon-CUL433-GT-TMBBQ-01e-CUL868-FS20-EMGZ-1W(GPIO)-DS18B20-CO2-USBRS232-USBRS422-Betty_Boop-EchoDot-OBIS(Easymeter-Q3/EMH-KW8)-PCA301(S'duino)-Deebot(mqtt2)-zigbee2mqtt