Samsung TV IP Control

Discussion in 'Pascal Logic Code Examples' started by djaggar, Sep 29, 2016.

  1. djaggar

    djaggar

    Joined:
    Jul 18, 2009
    Messages:
    66
    Likes Received:
    0
    Location:
    New Zealand
    Here is some code to control a Samsung TV over IP with a Wiser. My TVs can't be turned on over IP (I'm not sure any Samsung can), nor do they respond to a WOL, but you can turn the TV off this way, which is what I use the code for (my "house all off" scene triggers this code).

    This code will only run on a Wiser (not CTouch) because the TV protocol runs on port 55000 and CTouch can't access a port number that high.

    The protocol uses strings in Base64 format, there is a generic procedure to encode ASCII to Base64 format should anyone ever need such a thing ...

    So, there is one constant (put this in the constant section)
    Code:
    SamsungTVHandle = 1;
    which is the Wiser Client Socket number the code will use (leave it as 1 if you don't use any other sockets, otherwise change it to a free one)

    There are 4 global variables
    Code:
    Base64: array[0..63] of char;
    SamsungTVAuthString: array[0..82] of char;
    SamsungTVRespString: array[0..20] of char;
    SamsungTVKeyString: array[0..44] of char;
    Don't be tempted to declare these as string, the first two are too big for a Logic Engine string.

    Now the Base64 code, add a procedure called Base64Encode and paste this code in

    Code:
    procedure Base64Encode(input: string ; var output: string);
    var
      byte, triple, out, len: integer;
      outchar: char;
    begin
      if (Base64[0] <> 'A') then begin // initialise the dictionary
        for byte := 0 to 25 do begin
          Base64[byte] := chr(byte + 65); // uppercase
          Base64[byte + 26] := chr(byte + 97); // lowercase
          end;
        for byte := 0 to 9 do 
          Base64[byte + 52] := chr(byte + 48); // digits
        Base64[62] := '+';
        Base64[63] := '/';
        end;
          
      len := length(input);
      setlength(output,0);
      triple := 1;
      while (triple + 2) <= len do begin // at least 3 bytes left
        byte := (ord(input[triple]) shl 16) or (ord(input[triple+1]) shl 8) or ord(input[triple+2]);
        for out := 3 downto 0 do
          append(output,Base64[(byte shr (out * 6)) and 63]);   
        triple := triple + 3;
        end;
      if ((triple + 1) <= len) then begin // only two bytes left
        byte := (ord(input[triple]) shl 16) or (ord(input[triple+1]) shl 8);
        for out := 3 downto 1 do
          append(output,Base64[(byte shr (out * 6)) and 63]);
        append(output,'=');
        end
      else if ((triple) <= len) then begin // only one byte left
        byte := ord(input[triple]) shl 16;
        for out := 3 downto 2 do
          append(output,Base64[(byte shr (out * 6)) and 63]);
        append(output,'==');
        end
      end;
    Now a procedure that builds two strings needed initiate the TV protocol, add a procedure called SamsungTVBuildInitStrings and paste the following in
    Code:
    procedure SamsungTVBuildInitStrings;
    var
      ipencoded,
      authencoded,
      remoteencoded: string;
    begin
      Base64Encode('192.168.0.1',ipencoded); // any IP address seems to work here
      Base64Encode('6a:61:67:67:61:72',authencoded); // and any MAC address here 
      Base64Encode('CBus Remote',remoteencoded); // TV displays this string when authenticating
      format(SamsungTVAuthString,#$64,#$00,chr(length(ipencoded)),chr($00),ipencoded,chr(length(authencoded)),chr($00),authencoded,chr(length(remoteencoded)),#$00,remoteencoded);                          
      format(SamsungTVAuthString,#$00,chr(length('cbus.samsung')),#$00,'cbus.samsung',chr(length(SamsungTVAuthString)),#$00,SamsungTVAuthString);          
      format(SamsungTVRespString,#$00,chr(length('cbus.samsung')),#$00,'cbus.samsung',#2,#$00,#$c8,#$00);
    end;
    And one more procedure which builds a packet to actually make the TV do something, add a procedure called SamsungTVBuildKeyString and paste the following in

    Code:
    procedure SamsungTVBuildKeyString(key: string);
    var
      keyencoded: string;
    begin
      format(SamsungTVKeyString,'KEY_',key);
      Base64Encode(SamsungTVKeyString,keyencoded);
      format(SamsungTVKeyString,#$00,#$00,#$00,chr(length(keyencoded)),#$00,keyencoded);
      format(SamsungTVKeyString,#$00,chr(length('cbus.samsung')),#$00,'cbus.samsung',chr(length(SamsungTVKeyString)),#$00,SamsungTVKeyString);
    end;
    Finally the code to put in a module (this is just an example). After you paste the following code you have to put the IP address of the TV in the call to OpenClientSocket (on the 3rd line replace aaa.bbb.ccc.ddd). If you have a Group called "All Off Trigger" then the code will execute once and turn off the TV when that Group is turned on ...

    Code:
    once GetLightingState("All Off Trigger") then begin
      if NOT ClientSocketConnected(SamsungTVHandle) then begin
        OpenClientSocket(SamsungTVHandle, 'aaa.bbb.ccc.ddd', 55000);
        WaitUntil(ClientSocketConnected(SamsungTVHandle) OR (ClientSocketError(SamsungTVHandle)<>0));
        if not ClientSocketConnected(SamsungTVHandle) then
           ExitModule;
        SamsungTVBuildInitStrings;
        WriteClientSocket(SamsungTVHandle,SamsungTVAuthString);
        delay(0.2);
        WriteClientSocket(SamsungTVHandle,SamsungTVRespString);
        end;
      delay(0.2);
      SamsungTVBuildKeyString('POWEROFF');
      WriteClientSocket(SamsungTVHandle,SamsungTVKeyString);
      CloseClientSocket(SamsungTVHandle);
    end;
    The code
    Code:
    SamsungTVBuildKeyString('POWEROFF');
    WriteClientSocket(SamsungTVHandle,SamsungTVKeyString);
    near the end sends a power off command to the TV, you could put other stuff here (TOOLS is useful for testing ... it brings up the Tools menu on the TV), and a quick web search (try Samsung TV IP control KEY_POWEROFF) will show you other possibilities. The code adds KEY_ to the front of the name so leave that bit off when you call SamsungTVBuildKeyString.

    The first time the code runs the TV should prompt you to authenticate the connection to 'CBus Remote' (so the first key sequence gets dropped on the floor because the code doesn't wait) but once authenticated the TV should respond to your key requests. I haven't bothered waiting for responses from the TV, but you could if you want to send out multiple keys sequences, just read the client socket with an empty terminator string. If the TV can't be reached (e.g. it is already off) this code runs it waits for 20 seconds before giving up.

    The code could also be used to bring up a PIP or Web browser (SamsungTVBuildKeyString('RSS') will simulate the Smart button) on the TV when an event happens (like a security camera event).

    I've tested on my UA60ES8000 and UA75F6400, 2012 & 2013 models respectively, post a reply here if the code works with other TVs.
     
    djaggar, Sep 29, 2016
    #1
  2. djaggar

    Roosta

    Joined:
    Nov 22, 2011
    Messages:
    560
    Likes Received:
    1
    Location:
    Australia
    Very cool mate.. Top work..

    Thanks for sharing!!

    Cheers..
     
    Roosta, Sep 29, 2016
    #2
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.