Hi Peter,
ich bin da absolut kein Experte. Ich weiß ehrlich gesagt auch nicht, wie alt mein LG ist.
Ich kann’s aber versuchen.
Als Erstes legst du folgendes Skript an:
<?php
class webOSTV
{
private $host, $port, $ws_key, $path, $lg_key, $sock, $connected=false, $handshaked=false;
function __construct($host, $port=3000, $lgKey="NOKEY", $path="/")
{
$this->host = $host;
$this->port = $port;
$this->lg_key = $lgKey;
$this->path = $path;
$this->ws_key = $key = base64_encode(generateRandomString(16, false, true));
if ($this->lg_key=="NOKEY") unset($this->lg_key);
}
function connect()
{
$ws_handshake_cmd = "GET " . $this->path . " HTTP/1.1\r\n";
$ws_handshake_cmd.= "Upgrade: websocket\r\n";
$ws_handshake_cmd.= "Connection: Upgrade\r\n";
$ws_handshake_cmd.= "Sec-WebSocket-Version: 13\r\n";
$ws_handshake_cmd.= "Sec-WebSocket-Key: " . $this->ws_key. "\r\n";
$ws_handshake_cmd.= "Host: ".$this->host.":".$this->port."\r\n\r\n";
$this->sock = fsockopen($this->host, $this->port, $errno, $errstr, 2);
socket_set_timeout($this->sock, 0, 10000);
echo "Sending WS handshake\n$ws_handshake_cmd\n";
$response = $this->send($ws_handshake_cmd);
if ($response)
{
echo "WS Handshake Response:\n$response\n";
}
else
echo "ERROR during WS handshake!\n";
preg_match('#Sec-WebSocket-Accept:\s(.*)$#mU', $response, $matches);
if ($matches)
{
$keyAccept = trim($matches[1]);
$expectedResonse = base64_encode(pack('H*', sha1($this->ws_key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
$this->connected = ($keyAccept === $expectedResonse) ? true : false;
}
else $this->connected=false;
if ($this->connected); echo "Sucessfull WS connection to $this->host:$this->port\n\n";
return $this->connected;
}
function lg_handshake()
{
if (!$this->connected) $this->connect();
if ($this->connected)
{
$handshake = '{"type":"register","id":"register_0","payload":{"forcePairing":false,"pairingType":"PROMPT","client-key":"HANDSHAKEKEYGOESHERE","manifest":{"manifestVersion":1,"appVersion":"1.1","signed":{"created":"20140509","appId":"com.lge.test","vendorId":"com.lge","localizedAppNames":{"":"LG Remote App","ko-KR":"리모컨 앱","zxx-XX":"ЛГ R�мot� AПП"},"localizedVendorNames":{"":"LG Electronics"},"permissions":["TEST_SECURE","CONTROL_INPUT_TEXT","CONTROL_MOUSE_AND_KEYBOARD","READ_INSTALLED_APPS","READ_LGE_SDX","READ_NOTIFICATIONS","SEARCH","WRITE_SETTINGS","WRITE_NOTIFICATION_ALERT","CONTROL_POWER","READ_CURRENT_CHANNEL","READ_RUNNING_APPS","READ_UPDATE_INFO","UPDATE_FROM_REMOTE_APP","READ_LGE_TV_INPUT_EVENTS","READ_TV_CURRENT_TIME"],"serial":"2f930e2d2cfe083771f68e4fe7bb07"},"permissions":["LAUNCH","LAUNCH_WEBAPP","APP_TO_APP","CLOSE","TEST_OPEN","TEST_PROTECTED","CONTROL_AUDIO","CONTROL_DISPLAY","CONTROL_INPUT_JOYSTICK","CONTROL_INPUT_MEDIA_RECORDING","CONTROL_INPUT_MEDIA_PLAYBACK","CONTROL_INPUT_TV","CONTROL_POWER","READ_APP_STATUS","READ_CURRENT_CHANNEL","READ_INPUT_DEVICE_LIST","READ_NETWORK_STATE","READ_RUNNING_APPS","READ_TV_CHANNEL_LIST","WRITE_NOTIFICATION_TOAST","READ_POWER_STATE","READ_COUNTRY_INFO"],"signatures":[{"signatureVersion":1,"signature":"eyJhbGdvcml0aG0iOiJSU0EtU0hBMjU2Iiwia2V5SWQiOiJ0ZXN0LXNpZ25pbmctY2VydCIsInNpZ25hdHVyZVZlcnNpb24iOjF9.hrVRgjCwXVvE2OOSpDZ58hR+59aFNwYDyjQgKk3auukd7pcegmE2CzPCa0bJ0ZsRAcKkCTJrWo5iDzNhMBWRyaMOv5zWSrthlf7G128qvIlpMT0YNY+n/FaOHE73uLrS/g7swl3/qH/BGFG2Hu4RlL48eb3lLKqTt2xKHdCs6Cd4RMfJPYnzgvI4BNrFUKsjkcu+WD4OO2A27Pq1n50cMchmcaXadJhGrOqH5YmHdOCj5NSHzJYrsW0HPlpuAx/ECMeIZYDh6RMqaFM2DXzdKX9NmmyqzJ3o/0lkk/N97gfVRLW5hA29yeAwaCViZNCP8iC9aO0q9fQojoa7NQnAtw=="}]}}}';
if (isset($this->lg_key))
$handshake = str_replace('HANDSHAKEKEYGOESHERE',$this->lg_key,$handshake);
else $handshake = '{"type":"register","id":"register_0","payload":{"forcePairing":false,"pairingType":"PROMPT","manifest":{"manifestVersion":1,"appVersion":"1.1","signed":{"created":"20140509","appId":"com.lge.test","vendorId":"com.lge","localizedAppNames":{"":"LG Remote App","ko-KR":"리모컨 앱","zxx-XX":"ЛГ R�мot� AПП"},"localizedVendorNames":{"":"LG Electronics"},"permissions":["TEST_SECURE","CONTROL_INPUT_TEXT","CONTROL_MOUSE_AND_KEYBOARD","READ_INSTALLED_APPS","READ_LGE_SDX","READ_NOTIFICATIONS","SEARCH","WRITE_SETTINGS","WRITE_NOTIFICATION_ALERT","CONTROL_POWER","READ_CURRENT_CHANNEL","READ_RUNNING_APPS","READ_UPDATE_INFO","UPDATE_FROM_REMOTE_APP","READ_LGE_TV_INPUT_EVENTS","READ_TV_CURRENT_TIME"],"serial":"2f930e2d2cfe083771f68e4fe7bb07"},"permissions":["LAUNCH","LAUNCH_WEBAPP","APP_TO_APP","CLOSE","TEST_OPEN","TEST_PROTECTED","CONTROL_AUDIO","CONTROL_DISPLAY","CONTROL_INPUT_JOYSTICK","CONTROL_INPUT_MEDIA_RECORDING","CONTROL_INPUT_MEDIA_PLAYBACK","CONTROL_INPUT_TV","CONTROL_POWER","READ_APP_STATUS","READ_CURRENT_CHANNEL","READ_INPUT_DEVICE_LIST","READ_NETWORK_STATE","READ_RUNNING_APPS","READ_TV_CHANNEL_LIST","WRITE_NOTIFICATION_TOAST","READ_POWER_STATE","READ_COUNTRY_INFO"],"signatures":[{"signatureVersion":1,"signature":"eyJhbGdvcml0aG0iOiJSU0EtU0hBMjU2Iiwia2V5SWQiOiJ0ZXN0LXNpZ25pbmctY2VydCIsInNpZ25hdHVyZVZlcnNpb24iOjF9.hrVRgjCwXVvE2OOSpDZ58hR+59aFNwYDyjQgKk3auukd7pcegmE2CzPCa0bJ0ZsRAcKkCTJrWo5iDzNhMBWRyaMOv5zWSrthlf7G128qvIlpMT0YNY+n/FaOHE73uLrS/g7swl3/qH/BGFG2Hu4RlL48eb3lLKqTt2xKHdCs6Cd4RMfJPYnzgvI4BNrFUKsjkcu+WD4OO2A27Pq1n50cMchmcaXadJhGrOqH5YmHdOCj5NSHzJYrsW0HPlpuAx/ECMeIZYDh6RMqaFM2DXzdKX9NmmyqzJ3o/0lkk/N97gfVRLW5hA29yeAwaCViZNCP8iC9aO0q9fQojoa7NQnAtw=="}]}}}';
echo "Sending LG handshake\n$handshake\n";
$response = $this->send(hybi10Encode($handshake));
if ($response)
{
echo "\nLG Handshake Response\n".json_string($response)."\n";
$result = json_array($response);
if ($result && array_key_exists('id',$result) && $result['id']=='result_0' && array_key_exists('client-key',$result['payload']))
{
if ($this->lg_key == $result['payload']['client-key']);
echo "LG Client-Key successfully approved\n";
}
else if ($result && array_key_exists('id',$result) && $result['id']=='register_0' && array_key_exists('pairingType',$result['payload']) && array_key_exists('returnValue',$result['payload']))
{
if ($result['payload']['pairingType'] == "PROMPT" && $result['payload']['returnValue'] == "true")
{
$starttime = microtime(1);
$lg_key_received = false;
$error_received = false;
do
{
$response = @fread($this->sock, 8192);
$result = json_array($response);
if ($result && array_key_exists('id',$result) && $result['id']=='register_0' && is_array($result['payload']) && array_key_exists('client-key',$result['payload']))
{
$lg_key_received = true;
$this->lg_key = $result['payload']['client-key'];
echo "LG Client-Key successfully received: $this->lg_key\n";
}
else if ($result && array_key_exists('id',$result) && $result['id']=='register_0' && array_key_exists('error',$result))
{
$error_received = true;
echo "ERROR: ".$result['error']."\n";
}
usleep(200000);
$time = microtime(1);
}
while ($time-$starttime<60 && !$lg_key_received && !$error_received);
}
}
}
else echo "ERROR during LG handshake:\n";
}
else return FALSE;
}
function disconnect()
{
$this->connected=false;
@fclose($this->sock);
echo "Connection closed to $this->host\n";
}
function send($msg)
{
@fwrite($this->sock, $msg);
usleep(250000);
$response = @fread($this->sock, 8192);
return $response;
}
function send_command($cmd)
{
if (!$this->connected) $this->connect();
if ($this->connected)
{
echo "Sending command : $cmd\n";
$response = $this->send(hybi10Encode($cmd));
if ($response)
echo "Command response : ".json_string($response)."\n";
else
echo "Error sending command: $cmd\n";
return $response;
}
}
//Ab hier können Funktionen hinzugefügt werden
function turnOff() //Einschalten geht nur über WOL!
{
$command = '{"id":"turnOff","type":"request","uri":"ssap://system/turnOff"}';
$this->send_command($command);
}
function volumeUp()
{
$command = '{"id":"volumeUp","type":"request","uri":"ssap://audio/volumeUp"}';
$this->send_command($command);
}
function volumeDown()
{
$command = '{"id":"volumeDown","type":"request","uri":"ssap://audio/volumeDown"}';
$this->send_command($command);
}
function message($msg)
{
$command = '{"id":"message","type":"request","uri":"ssap://system.notifications/createToast","payload":{"message":"'.$msg.'"}}';
$this->send_command($command);
}
function set_volume($vol)
{
//$command = '{"id":"setVolume","type":"request","uri":"ssap://audio/setVolume","payload":{"volume":'.$vol.'"}}';
$command = "{\"id\":\"set_volume\",\"type\":\"request\",\"uri\":\"ssap://audio/setVolume\",\"payload\":{\"volume\":$vol}}";
$this->send_command($command);
}
}
function hybi10Encode($payload, $type = 'text', $masked = true) {
$frameHead = array();
$frame = '';
$payloadLength = strlen($payload);
switch ($type) {
case 'text':
$frameHead[0] = 129;
break;
case 'close':
$frameHead[0] = 136;
break;
case 'ping':
$frameHead[0] = 137;
break;
case 'pong':
$frameHead[0] = 138;
break;
}
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]);
}
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;
}
foreach (array_keys($frameHead) as $i)
{
$frameHead[$i] = chr($frameHead[$i]);
}
if ($masked === true)
{
$mask = array();
for ($i = 0; $i < 4; $i++)
{
$mask[$i] = chr(rand(0, 255));
}
$frameHead = array_merge($frameHead, $mask);
}
$frame = implode('', $frameHead);
for ($i = 0; $i < $payloadLength; $i++)
{
$frame .= ($masked === true) ? $payload[$i] ^ $mask[$i % 4] : $payload[$i];
}
return $frame;
}
function generateRandomString($length = 10, $addSpaces = true, $addNumbers = true)
{
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"§$%&/()=[]{}';
$useChars = array();
for($i = 0; $i < $length; $i++)
{
$useChars[] = $characters[mt_rand(0, strlen($characters)-1)];
}
if($addSpaces === true)
{
array_push($useChars, ' ', ' ', ' ', ' ', ' ', ' ');
}
if($addNumbers === true)
{
array_push($useChars, rand(0,9), rand(0,9), rand(0,9));
}
shuffle($useChars);
$randomString = trim(implode('', $useChars));
$randomString = substr($randomString, 0, $length);
return $randomString;
}
function json_array($str)
{
$result = json_decode(json_string($str),true);
return $result;
}
function json_string($str)
{
$from = strpos($str,"{");
$to = strripos($str,"}");
$len = $to-$from+1;
$result = substr($str,$from,$len);
return $result;
}
?>
Danach ein weiteres:
<?php
//1. TV Einschalten und Einstellungen im TV für Steuerung via App usw. prüfen ob aktiviert
include_once '12345.ips.php'; //2. Skript ID des "webos.inc.php" Skript eintragen
$tv = new webOSTV("192.168.x.x",3000,""); //3. IP des TV eintragen
$tv->connect();
$tv->lg_handshake();
$tv->disconnect();
//4. Skript ausführen
//5. Meldung am TV beachten und akzeptieren (kurzes Zeitfenster)
//6. Response abwarten und LG Client-Key notieren. "LG Client-Key successfully received: 0afd4c4xxxxxxxxxx..."
//7. Mit einem neuen Skript befehle testen
?>
Im zweiten Skript wird unter Punkt 2 die ID des ersten Skript’s eingetragen und unter Punkt 3 die IP des LG. Dieses Skript wird nur einmal ausgeführt und erzeugt den Client-Key, welcher für die Befehls-Skripte benötigt wird.
Ein solches Skript z.B. für die Lautstärke sieht dann so aus:
<?php
include_once '17551.ips.php';
$vol = "25";
$tv = new webOSTV("192.168.x.x",3000,"abcd08fc19e14abcdb1234b3db67ca99"); // Change to the IP of your LG device //
$tv->lg_handshake();
$tv->set_volume($vol);
?>
Oder hier für einen Meldetext:
<?php
include_once '17551.ips.php';
$msg = GetValueString(56560); // ID der Meldetextvariable //
$tv = new webOSTV("192.168.x.x",3000,"abcd08fc19e14abcdb1234b3db67ca99"); // Change to the IP of your LG device //
$tv->lg_handshake();
$tv->message($msg);
?>
Hier gab es auch noch mehrere andere Möglichkeiten, ansonsten suche ich die noch raus.
Das alles ist aber nicht auf meinen Mist gewachsen, das habe ich mir halt durch mehrere Recherchen herausgesucht und mit PHP kenne ich mich kaum aus.
Noch wichtig. Man kann den LG auch einschalten. Das hängt aber davon ab, ob der schon im Tiefschlaf ist oder sich noch anpingen lässt. Antwortet er nicht auf einen Ping, dann muss er mit WOL aufgeweckt werden. Da gibt’s auch etwas zu. Lässt er sich noch anpingen, geht das wiederum mit einem Skript.
Weiterhin sollte man nach einem WOL Start mindestens 30 Sekunden warten, bevor man ihn via Skript anspricht. Manchmal führt er dann zwar die Befehle aus, erzeugt aber mangels Response Fehlermeldungen im PHP-Skript.
Ich hoffe ich konnte dir als Laie etwas helfen. Sonst einfach fragen.
Gruß
Marc