Websocket

Hallo,

Ich steht vor einem Problem.
Ich will über eine Websocketverbindung Daten einlesen.
Die Verbindung habe ich über ein PHP Skript mir pfsockopen geöffnet.

Wie bekomme ich jetzt mit, dass Daten über den socket empfangen wurden???

Oder gibt es eine andere Möglichkeit einen WEbsocket zu öffnen

Ich denke, hier versteht man dein eigentliches Problem nicht.
Beschreibe doch mal näher was du vor hast und worauf du hinaus willst;)

Hi zusammen,

ich häng mich mal an diesen Thread ran, weil es bei mir auch aktuell um einen Websocket geht.
Ich muss vorab schieben, dass ich nur grundlegende Coding-Skills habe :wink: und auch in IPS recht neu bin. Bin also über jede Hilfe dankbar!

Eine vorhandene Applikation auf einem Server sendet über einen Websocket regelmäßig Statusmeldungen, welche ich gerne in IPS visualisieren möchte.

Meine mangelnden Kenntnisse erlauben mir derzeit:
Mit www.websocket.org (Demo Echo Test) kann ich die IP der Applikation angeben und connecten. Darauf erhalte ich ein „HELLO“. Dann muss ich einen mir bekannten Connect-String senden. Im Anschluß trudeln im Sekundentakt die Statusmeldungen ein.

  1. Was brauche ich in IPS? Client Socket oder Server Socket?

  2. Wie sende ich den Connect-String?

  3. Wie arbeite ich mit den Statusmeldungen am Sinnvollsten weiter? Die regelmäßig eintrudelnden Meldungen haben etwa das folgende Format:

RESPONSE: LS:Busy/Turbine1Running, Turbine2Running, Attached/False/Closed/374,08x104,676x37,762

Aus der jeweils letzten Meldung möchte ich mit einem Skript berechnen, ob die Turbine läuft, ob die App Attached ist oder nicht und muss mit den Zahlen weitere Berechnungen anstellen.

DANKE im Vorraus :wink:
Michael

Hallo,

zu 2:
vielleicht helfen dir die Fritzbox Scripte, dort sieht das so aus:

//Anrufliste aktualisieren
$postdata = http_build_query(array(
    'getpage' => '../html/de/menus/menu2.html','sid' => $SID,
   'var:menu' => 'home', 'var:pagename' => 'foncalls'
));
$opts = array('http' => array(
    'method'  => 'POST',
    'header'  => 'Content-Length: '.strlen($postdata).CRLF.'Content-Type: application/x-www-form-urlencoded',
     'content' => $postdata
));

$context    = stream_context_create($opts);
$getnewlist = file_get_contents($fritzgui, false, $context);

Schöne Grüße
Thomas

Hi Thomas,

danke für deine Antwort.
Wenn ich das richtig sehe, wird da allerdings „nur“ die Webseite der Fritzbox geparst. Das möchte ich eigentlich vermeiden und lieber gemäß Websocket-Protokoll nativ den Socket ansprechen.
Dass ich oben www.websocket.org genannt habe, war nur zur Verdeutlichung worum es sich handelt - die Seite ist nicht in meinem Herrschaftsbereich :wink:

Viele Grüße,
Michael

Websockets könnten eine interessante Methode zur Integration zwischen JavaScript in eigenen Webseiten und IPS sein. Damit kann eine asynchrone Kommunikation aufgebaut werden und man spart sich das Pollen!

Ich bin mir nicht sicher, aber müsste dazu nicht der Webserver in IPS aufgebohrt werden (ws://)?

Das wäre natürlich die perfekte Integration…

Wenn IPS nur als Client sich auf einem Websocket verbinden soll braucht es den Webserver von IPS nicht.
Es reicht ein Clientsocket, aber das Protokoll musst du dann wohl selbst umsetzen in php.
Alternative wäre eine IO-Instanz welche das Protokoll spricht.
Auch fertige PHP Lösungen werden da kaum helfen, da wir in IPS PHP-Scripte nur durch Events (z.B. RegVar) triggern und ja kein Script als endlosschleife / dienst laufen lassen können.
Michael

Ich denke gerade über die andere Richtung (Webseite->IPS) nach.
Die Frage wäre, ob der Webserver, das das Webfront anbietet endlose PHP Skripte verkraftet. Dann könnte man dort einen Client/Server unterbringen. Perfekt wäre natürlich eine Websocket Client/Server Instanz in IPS :wink:

Imho gilt das 30 Sek Limit auch für Script welche durch den Webserver ausgeführt werden. Glaube auch kaum das der Webserver in IPS das verkraftet.
Das wäre dann ja eine Fremd (Websocket-Client) zu IPS (Websocket-Server) Verbindung.
Da wäre das erste wohl einfacher umzusetzen.
Zumal wenn die Fremd-HW/SW nur einen Websocket als Server bereitstellt.
Dann hast du ja keine andere Chance.
Michael

Blickt ihr bei den ganzen gleichen Themen noch durch? :smiley:

Websocket

Fragen zu „Einfache-eigene-Seiten-mit-JSON-RPC-Dojo-Javascript-ab-IP-Symcon-2-6“

Wie reagiert man in einer eigenen HTML Seite auf Änderungen?

-Chris-

Chris,
Websocket ist durchaus was völlig anderes.

Ich wäre immer noch daran interessiert - ohne weiteren Support (ggf. auch durch Implementierung eines Moduls durch die IPS-Entwickler) übersteigt das Thema aber schlichtweg meine Fähigkeiten fg

Ich sag ja nicht, dass das Thema nicht interessant wäre :slight_smile: Aber einige viele Beiträge, in genannten Threads, zielen immer auf das gleiche Thema ab :wink:

Grüße,
Chris

WebSocket Support ist angedacht - ich kann euch aber nicht sagen, wann wir es anbieten werden.
Ihr habt aber definitiv recht, dass es das Pollen erspart und weniger Latenz und weniger Bandbreite bedeutet.

paresy

Danke paresy!

Sorry Chris, aber wenn ich das lese bekomme ich pickel. Warum fällt dir nichts besseres ein? Vor allem da du in deinen Links genau auf den gleichen Artikel verlinkst :mad:

Meine Antwort:
Man kann doch in IPS einen ServerSocket erstellen, daran eine RegisterVariable binden und dann kann ich alles was an anfragen kommt, selbst auswerten und antworten senden. Damit wäre im. Prinzip auch ein WebServer möglich.

Das gleiche mache ich hier in meinem Script auch : SONOS-PHP-Class

cu. Xaver

@Xavar: Hab ich was gegen dich gesagt? Nein! Hab ich was böses gesagt? Nein!
…also wo ist dein Problem? Wenn es was persönliches ist, dann kannst du dich gerne per PN darüber mit mir unterhalten, hier werde ich nicht mehr drauf reagieren. Ansonsten entspann dich, keiner will dir was und ich schon gar nicht :slight_smile:

Grüße,
Chris

Hi,
ich hab mein Problem übrigens lösen können.
Falls es jemanden interessiert nachfolgend mein Skript.

Ein „fremder“ Websocket-Server sendet nach Übermittlung eines Connect-Strings zyklisch Meldungen, die ich somit in mein IPS einlese. Dazu ist in IPS ein Client-Socket und eine Registervariable angelegt. Letztere triggert das nachfolgende Skript.
Bei manuellem Aufruf des Skriptes wird der Connect zum WebSocket-Server hergestellt.


<?

function hybi10MyEncode($payload, $type = 'text', $masked = true) {
        $frameHead = array();
        $frame = '';
        $payloadLength = strlen($payload);

        switch ($type) {
            case 'text':
                // first byte indicates FIN, Text-Frame (10000001):
                $frameHead[0] = 129;
                break;

            case 'close':
                // first byte indicates FIN, Close Frame(10001000):
                $frameHead[0] = 136;
                break;

            case 'ping':
                // first byte indicates FIN, Ping frame (10001001):
                $frameHead[0] = 137;
                break;

            case 'pong':
                // first byte indicates FIN, Pong frame (10001010):
                $frameHead[0] = 138;
                break;
        }

        // set mask and payload length (using 1, 3 or 9 bytes)
        if ($payloadLength > 65535) {
            $payloadLengthBin = str_split(sprintf('%064b', $payloadLength), 8);
            $frameHead[1] = ($masked === true) ? 255 : 127;
            for ($i = 0; $i < 8; $i++) {
                $frameHead[$i + 2] = bindec($payloadLengthBin[$i]);
            }

            // most significant bit MUST be 0 (close connection if frame too big)
            if ($frameHead[2] > 127) {
                $this->close(1004);
                return false;
            }
        } elseif ($payloadLength > 125) {
            $payloadLengthBin = str_split(sprintf('%016b', $payloadLength), 8);
            $frameHead[1] = ($masked === true) ? 254 : 126;
            $frameHead[2] = bindec($payloadLengthBin[0]);
            $frameHead[3] = bindec($payloadLengthBin[1]);
        } else {
            $frameHead[1] = ($masked === true) ? $payloadLength + 128 : $payloadLength;
        }

        // convert frame-head to string:
        foreach (array_keys($frameHead) as $i) {
            $frameHead[$i] = chr($frameHead[$i]);
        }

        if ($masked === true) {
            // generate a random mask:
            $mask = array();
            for ($i = 0; $i < 4; $i++) {
                $mask[$i] = chr(rand(0, 255));
            }

            $frameHead = array_merge($frameHead, $mask);
        }
        $frame = implode('', $frameHead);
        // append payload to frame:
        for ($i = 0; $i < $payloadLength; $i++) {
            $frame .= ($masked === true) ? $payload[$i] ^ $mask[$i % 4] : $payload[$i];
        }

        return $frame;
    };
    
    
function hybi10Decode($data)
{
    $bytes = $data;
    $dataLength = '';
    $mask = '';
    $coded_data = '';
    $decodedData = '';
    $secondByte = sprintf('%08b', ord($bytes[1]));
    $masked = ($secondByte[0] == '1') ? true : false;
    $dataLength = ($masked === true) ? ord($bytes[1]) & 127 : ord($bytes[1]);

    if($masked === true)
    {
        if($dataLength === 126)
        {
           $mask = substr($bytes, 4, 4);
           $coded_data = substr($bytes, 8);
        }
        elseif($dataLength === 127)
        {
            $mask = substr($bytes, 10, 4);
            $coded_data = substr($bytes, 14);
        }
        else
        {
            $mask = substr($bytes, 2, 4);
            $coded_data = substr($bytes, 6);
        }
        for($i = 0; $i < strlen($coded_data); $i++)
        {
            $decodedData .= $coded_data[$i] ^ $mask[$i % 4];
        }
    }
    else
    {
        if($dataLength === 126)
        {
           $decodedData = substr($bytes, 4);
        }
        elseif($dataLength === 127)
        {
            $decodedData = substr($bytes, 10);
        }
        else
        {
            $decodedData = substr($bytes, 2);
        }
    }

    return $decodedData;
};



if($IPS_SENDER == "RegisterVariable") {
	$rawdata=$IPS_VALUE;
	$data=hybi10Decode($rawdata);
        // ...hier hab ich die empfangenen Daten noch für mich aufbereitet
	SetValue(1234,$data);

	} else {
	
if (IPS_GetInstance(98765 /*[WS-ClientSocket]*/)["InstanceStatus"]=102) {         //Status 102 ist "Socket offen", sonst ist es "geschlossen" oder "Fehler"

$host = '192.168.1.150';  // IP des Websocket-Server
$port = 80;
$local = "192.168.1.123";  // IP vom IPS-Server
$data = "mein-string-der-beim-connect-gesendet-wird";  

$head = "GET / HTTP/1.1"."
".
        "Upgrade: WebSocket"."
".
        "Connection: Upgrade"."
".
        "Origin: $local"."
".
        "Host: $host"."
".
        "Sec-WebSocket-Version: 13"."
".
        "Sec-WebSocket-Key: asdasdaas76da7sd6asd6as7d"."
".
        "Content-Length: ".strlen($data)."
"."
";

CSCK_SetOpen(98765 /*[WS-ClientSocket]*/,true);
IPS_ApplyChanges(98765 /*[WS-ClientSocket]*/);
CSCK_SendText(98765 /*[WS-ClientSocket]*/,$head);
CSCK_SendText(98765 /*[WS-ClientSocket]*/, hybi10MyEncode($data));


	}  else {
// hier führe ich diverse Aktionen aus, falls der Client-Socket geschlossen bzw. auf Fehler ist (WebSocket-Server neustarten etc.)
	};
	
	};

?>




Ist es denn möglich Ratchet (Ratchet - PHP WebSockets) mit IP-Symcon zu nutzen? Hat das jemand mal probiert?

Welchen Server benutzt Du als Websocket-Server?

Ist das denn angedacht das dies mit IP-Symcon 4 kommen wird?