This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Sony Bravia Authentication
#1
Is there anybody who got the IP Control function of the more recent Sony Bravia TV working? I'm able to post a HTTP request trough my phone, only after pairing the device with the TV first with the default sony app. On my PC this is a little more complicated, but after following this guide (post Jul 08, 2015) this seems to work correctly. The PC appears on my TV in the list of trusted devices, along with my phone. The POST request requires to input a pincode visualized on the screen after starting the request.


Quote:1. Install Google Chrome
2. Install Simple Rest Client (https://chrome.google.com/webstore/detail/simple-rest-client/fhjcajmcbmldlhcimfajhfbgofnpcjmb)
3. Once Simple Rest Client is installed you should see a blue globe looking icon to the right of the URL field in Chrome. Click on that icon.
4. In the URL field of the REST Client, type in http://192.168.168.198/sony/accessControl
where you replace 192.168.168.198 with IP address of your TV.
5. Click on POST.
6. In the DATA field paste:

{"id":13,"method":"actRegister","version":"1.0","params":[{"clientid":"iRule:1","nickname":"iRule"},[{"clientid":"iRule:1","value":"yes","nickname":"iRule","function":"WOL"}]]}


7. Hit SEND. You should see a message on TV pop-up with PIN code and a Username and Password message pop-up in the Browser.
Leave Username blank and in password field put in the PIN code that is displayed on TV.

It seems the TV needs to trust the device sending requests. Is there a way to enable this with the logicmachine? Previous threads don't seem to work in my case (Sony Bravia script and Sony Simple IP Protocol).


This is the code I tried to use:
Code:
function ipControlTV(service, cmd)   
 
  require('socket')
 
  ip = "192.168.1.135"
  port = 80
 
  host = "http://" .. ip .. "/sony/" .. service
  reqs = "POST /sony/" .. service .. " HTTP/1.1 \r\n" ..
            "HOST: " .. ip .. " \r\n" ..
            "X-Auth-PSK: **** \r\n" ..
            "Content-Type: application/json; charset=UTF-8 \r\n " ..
            "\r\n" .. cmd .. "\r\n\r\n"
 
  sock = socket.tcp()
  sock:settimeout(3)

  res, err = sock:connect(ip, port)
  if res then
    res, err = sock:send(reqs)

    if res then
      log(res,err)
    else
      log('send failed: ' .. tostring(err))
    end
  else
    log('connect failed: ' .. tostring(err))
  end

  sock:close()
end

And to call my code (toggle of power object):
Code:
power = event.getvalue()
command = ""

if (power) then
  command =  '{ \\"method\\": \\"setPowerStatus\\", \\"id\\": 55, \\"params\\": [{\\"status\\": true}], \\"version\\": \\"1.0\\" }'
else
  command = '{ \\"method\\": \\"setPowerStatus\\", \\"id\\": 55, \\"params\\": [{\\"status\\": false}], \\"version\\": \\"1.0\\" }'
end

ipControlTV("system", command)

I keep getting the following error:
Code:
* arg: 1
  * string: JSON Format Error
* arg: 2
  * number: 400
Reply
#2
Just remove all \\ from command strings.
More correct approach is to encode data via JSON:
Code:
require('json')
power = event.getvalue()

command = json.encode({
  method = 'setPowerStatus',
  id = 55,
  version = '1.0',
  params = {
    { status = power }
  }
})

ipControlTV("system", command)
Reply
#3
Hi, 

Why do you try Http post command to a tcp socket??

Try this, i have it working on Sony 2019 tv with no auth required as such (apart from the Xauth-psk as defined in the tv settings) also the protocol is well documented here
https://pro-bravia.sony.net/develop/inte...index.html
i just started learning lua so im sure there are some improvements to make to this script.

Change ip adress below to match tv and update ["X-Auth-PSK"] = "123456789", with your pre shared key from the tv


Code:
local http = require("socket.http")
local ltn12 = require("ltn12")
require('json')

local path_system = "http://192.168.1.21/sony/system"
local path_avContent = 'http://192.168.1.21/sony/avContent'

  local payl = {
    Pwr_on = [[ {"method": "setPowerStatus","id": 55,"params": [{"status": true}],"version": "1.0"} ]], --/system
    Pwr_off = [[ {"method": "setPowerStatus","id": 55,"params": [{"status": false}],"version": "1.0"} ]], --/system
    Pwr_req = [[ {"method": "getPowerStatus","id": 50,"params": [],"version": "1.0"} ]], --/system
    Pwr_Get_system =  [[{"method": "getSystemInformation","id": 33,"params": [],"version": "1.0"}]],
   
    Set_input_hdmi3 = [[ {"method": "setPlayContent","id": 101,"params": [{"uri": "extInput:hdmi?port=3"}],"version": "1.0"} ]], --/avContent
    Set_req = [[ {"method": "getPlayingContentInfo","id": 103,"params": [],"version": "1.0"} ]],   --/avContent
 
    vol_set = [[ {"method": "setAudioVolume","id": 98,"params": [{"volume": "5","ui": "on","target": "speaker"}],"version": "1.2"} ]], -- /audio
    vol_req = [[ {"method": "getVolumeInformation", "id": 33, "params": [], "version": "1.0"} ]], -- /audio
   
    reboot = [[ {"method": "requestReboot","id": 10,"params": [],"version": "1.0"} ]]  --/system
  }


--********///////////// Main Command ////////////********-- 
function sony_do_cmd(sony_cmd) -- 'Pwr_on' , 'Pwr_off'  for power on call function,  sony_do_cmd('Pwr_on')
 
  -- is pwr command set url
  pwr = string.match(sony_cmd, "Pwr_")
  set = string.match(sony_cmd, "Set_")
 
  if pwr then
    path =  path_system
    payload = payl[sony_cmd]
  end
 
  if set then
    path =  path_avContent
    payload = payl[sony_cmd]
  end
 

  local response_body = { }
  local res, code, response_headers, status = http.request
  {
    url = path,
    method = "POST",
    headers =
    {
      ["Accept"] = "*/*",
      ["Content-Type"] = "application/x-www-form-urlencoded",
      ["X-Auth-PSK"] = "123456789",
      ["Content-Length"] = payload:len()
    },
   
    source = ltn12.source.string(payload),        
  sink = ltn12.sink.table(response_body)
  }
 

    log(json.decode(response_body)) 
 
  end
 
Reply
#4
Thanks @benanderson_475 for pointing me in the right direction! Everything is working as it should, guess I got a little mixed up. The guide is indeed self explanatory.
Reply
#5
I cleaned up your code a little to be tailored more to my needs. Also included a status object checker, convenient to get a feedback of the actual settings of the TV. 

   

Common Functions:
Code:
function ipControlSonyTV(service, command) 
  local http = require("socket.http")
  local ltn12 = require("ltn12")
  require("json")

  local ip = "192.168.1.135"
 
  local response_body = { }
  local res, code, response_headers, status = http.request
  {
    url = "http://" .. ip .. "/sony/" .. service,
    method = "POST",
    headers =
    {
      ["HOST"] = ip,
      ["Accept"] = "*/*",
      ["Content-Type"] = "application/x-www-form-urlencoded",
      ["X-Auth-PSK"] = "************",
      ["Content-Length"] = command:len()
    },
    source = ltn12.source.string(command),       
    sink = ltn12.sink.table(response_body)
  }
 
  response = json.decode(response_body[1])
  return response["result"][1]
end

Resident Script (every 2 seconds or as much as needed):
Code:
command = [[ {"method": "getPowerStatus","id": 50,"params": [],"version": "1.0"} ]]
powerStatus = ipControlSonyTV("system", command)
powerStatus = powerStatus["status"]

if (powerStatus == "active") then
  grp.checkwrite('5/0/2', 1, 1)
elseif (powerStatus == "standby") then
  grp.checkwrite('5/0/2', 0, 1)
end

if (powerStatus == "active") then
  command = [[ {"method": "getVolumeInformation", "id": 33, "params": [], "version": "1.0"} ]]
  volumeInfo = ipControlSonyTV("audio", command)
  volumeStatus = volumeInfo[1]["volume"]
  muteStatus = volumeInfo[1]["mute"]
  grp.checkwrite('5/0/5', volumeStatus, 1)
  grp.checkwrite('5/0/7', muteStatus, 1)
 
  command = [[ {"method": "getPlayingContentInfo","id": 103,"params": [],"version": "1.0"} ]]
  sourceStatus = ipControlSonyTV("avContent", command)
  sourceStatus = sourceStatus["uri"]
  sourceStatus = tonumber(string.sub(sourceStatus, -1))
  grp.checkwrite('5/0/9', sourceStatus, 1)
end

Every control object has it's own event script
Power:
Code:
power = event.getvalue()

if (power) then
  command = [[ {"method": "setPowerStatus","id": 55,"params": [{"status": true}],"version": "1.0"} ]]
else
  command = [[ {"method": "setPowerStatus","id": 55,"params": [{"status": false}],"version": "1.0"} ]]
end

ipControlSonyTV("system", command)

Volume Step:
Code:
volumeDown = event.getvalue()  -- down = 1 | up = 0

if (volumeDown) then
  command = [[ {"method": "setAudioVolume","id": 98,"params": [{"volume": "-1","ui": "on","target": "speaker"}],"version": "1.2"} ]]
else
  command = [[ {"method": "setAudioVolume","id": 98,"params": [{"volume": "+1","ui": "on","target": "speaker"}],"version": "1.2"} ]]
end

ipControlSonyTV("audio", command)

Volume:
Code:
volume = event.getvalue()

command = [[ {"method": "setAudioVolume","id": 98,"params": [{"volume": "]] .. volume .. [[","ui": "on","target": "speaker"}],"version": "1.2"} ]]

ipControlSonyTV("audio", command)

Mute:
Code:
mute = event.getvalue()

if (mute) then
  command = [[ {"method": "setAudioMute","id": 601,"params": [{"status": true}],"version": "1.0"} ]]
else
  command = [[ {"method": "setAudioMute","id": 601,"params": [{"status": false}],"version": "1.0"} ]]
end

ipControlSonyTV("audio", command)

Source Select:
Code:
source = event.getvalue()
power = grp.getvalue('5/0/2')

if (not power) then
  grp.write('5/0/1', 1)
  os.sleep(1)
end

command = [[ {"method": "setPlayContent","id": 101,"params": [{"uri": "extInput:hdmi?port=]] .. source .. [["}],"version": "1.0"} ]]

ipControlSonyTV("avContent", command)
Reply
#6
in case anyone can use it, Updated user library for sony tv ip control

Code:
require('json')

Sony_ip = '192.168.1.6'
X_Auth_Psk = "XXXXXXX9"

path_system = '/sony/system'
path_avContent = '/sony/avContent'
path_audio = '/sony/audio'
path_ircc = '/sony/IRCC'

function Sony_request(host, url,  payload)
 
  ltn12 = require('ltn12')
  http = require('socket.http')
  response_body = {}

  res, err = http.request{
    url = 'http://' .. host .. url,
    method = 'POST',
    headers =
    {
      ["Accept"] = "*/*",
      ["Content-Type"] = "application/x-www-form-urlencoded",
      ["X-Auth-PSK"] = X_Auth_Psk,
      ["Content-Length"] = payload:len()
    },
      source = ltn12.source.string(payload),
    sink = ltn12.sink.table(response_body)
  }

  if response_body then
   -- log(response_body)
    resp = json.encode(response_body)
     resp = json.decode(resp)
   -- log(resp) 
    if resp[2] then
      resp = table.concat(resp)
     resp = json.decode(resp)
    else             
    resp = json.decode(resp[1])
    end
   
   return resp
   
  else
    return nil, err
  end
end

function Sony_Soap_request(host, url, IRCC)
 
local body, http, ltn12, sink, res, err
  ltn12 = require('ltn12')
  http = require('socket.http')
 
  body = [[<?xml version="1.0"?>
  <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
   s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <s:Body>
  <u:X_SendIRCC xmlns:u="urn:schemas-sony-com:service:IRCC:1">
  <IRCCCode>]]..IRCC..[[</IRCCCode>
  </u:X_SendIRCC>
  </s:Body></s:Envelope>]]
 
  Soap_response_body = {}

  res, err = http.request{
    url = 'http://' .. host .. url,
    method = 'POST',
    headers =
    {
      ["Host"] = host,
      ["Connection"] = "keep-alive",
      ["Accept"] = "*/*",
      ["Content-Type"] = "text/xml; charset=UTF-8",
      ["X-Auth-PSK"] = X_Auth_Psk,
      ["Content-Length"] = #body,
      ["Soapaction"] = '"urn:schemas-sony-com:service:IRCC:1#X_SendIRCC"'
    },
 
    source = ltn12.source.string(body),
    sink = ltn12.sink.table(Soap_response_body)
  }

  if Soap_response_body then
    return Soap_response_body
  else
    return nil, err
  end
end


function encode_json_message(method, id, params, version)
  json_msg = json.encode({
      method = method,
      id = id,
      params = {params},
      version = version
        }) 
  return json_msg
end 

--************************* Command  functions ****************************
function Sony_pwr(state)
   Sony_request(Sony_ip, path_system, encode_json_message("setPowerStatus", 55, {status = state }, "1.0"))
end

function Sony_set_input_hdmi1()
   Sony_request(Sony_ip, path_avContent, encode_json_message("setPlayContent", 101, {uri = "extInput:hdmi?port=1"}, "1.0"))
end

function Sony_set_input_hdmi2()
   Sony_request(Sony_ip, path_avContent, encode_json_message("setPlayContent", 101, {uri = "extInput:hdmi?port=2"}, "1.0"))
end

function Sony_set_input_hdmi3()
   Sony_request(Sony_ip, path_avContent, encode_json_message("setPlayContent", 101, {uri = "extInput:hdmi?port=3"}, "1.0"))
end

function Sony_set_input_tv()
   Sony_request(Sony_ip, path_avContent, encode_json_message("setPlayContent", 101, {uri = "tv:dvbt"}, "1.0"))
end

function Sony_set_volume(level)
  res = Sony_request(Sony_ip, path_audio, encode_json_message("setAudioVolume", 98, {volume = level, ui = "on", target = ""}, "1.2"))
end 

function Sony_set_audio_mute(state)
   Sony_request(Sony_ip, path_audio, encode_json_message("setAudioMute", 601, {status = state}, "1.0"))
end

--************************* Request Command functions ****************************
function Sony_get_playing_content()
  json_msg = encode_json_message("getPlayingContentInfo", 103, {}, "1.0")
  res = Sony_request(Sony_ip, path_avContent, json_msg)
  --- update obj with new value
 
  if not res.error then -- cant call this function if the display is off res.error[2] =  Display Is Turned off
  title =  res.result[1].title
  programme = res.result[1].programTitle
  if title then
      grp.write('1/1/1', title)
  end 
  if programme then
    grp.write('1/1/2', programme)
  end
  end 
  return title, programme
end

function Sony_get_power_status()
  pwr_res = Sony_request(Sony_ip, path_system, encode_json_message("getPowerStatus", 50, {}, "1.0"))
  pwr_res = pwr_res.result[1].status --active|standby
  return pwr_res
end

function Sony_get_volume_info()
  vol_res = Sony_request(Sony_ip, path_audio, encode_json_message("getVolumeInformation", 33, {}, "1.0"))
  vol_res = vol_res.result[1][1].volume -- returns tv volume level
  return vol_res 
end

function Sony_get_remoteController_info()
  res = Sony_request(Sony_ip, path_system, encode_json_message("getRemoteControllerInfo", 54, {}, "1.0"))
  rc_codes = {}
  res = res.result[2]
  for i = 1, #res do
    name = res[i].name
    value = res[i].value
    rc_codes[name] = value 
end
-- log(rc_codes)
  storage.set('RC_Codes', rc_codes)
  return rc_codes
end

function req_channel_delayed(delay)
     os.sleep(delay)
     Sony_get_playing_content()
end

function Sony_send_key(IRCC_name) -- needs to send ircc with soap command...
--PartnerApp11, SyncMenu, FeaturedApp, MuteOff, MuteOn, AudioMixUp Teletext, AudioOutput_TVSpeaker, partnerApp10, BS, ActionMenu, SleepTimer
--CS, AudioMixDown, TvInput, PartnerApp1, Forward, Hdmi3, DigitalToggle, Hdmi2, PartnerApp6, ApplicationLauncher, Blue, Stop, TvAntennaCable,
--Wide, Help, AudioOutput_AudioSystem, VolumeDown, Hdmi1, Tv, PartnerApp20, OneTouchTimeRec, Down, PartnerApp19, PopUpMenu, FeaturedAppVOD,
--Component2, Video1, Audio, Media, Digital, Num11, PartnerApp13, Mode3D, AndroidMenu, *AD, Component1, CursorRight, Enter, PhotoFrame, Sleep,
--PartnerApp2, Assists, ChannelUp, Right, DOT, RecorderMenu, FootballMode, Green, PartnerApp14, GooglePlay, AudioOutput_Toggle, EPG, SubTitle,
--FlashMinus, Input, PartnerApp18, PartnerApp5, ClosedCaption, PartnerApp16, PAP, PartnerApp15, PartnerApp12, PartnerApp9, TenKey, WakeUp
--PartnerApp7, PartnerApp17, Next, PartnerApp4, PartnerApp3, Analog, PictureMode, STBMenu, TvSatellite, Jump, BSCS, Rec, Hdmi4, Ddata, YouTube
--Mute, ChannelDown, OneTouchView, Home, AnalogRgb1, PictureOff, Num2, TvAnalog, Tv_Radio, , CursorDown, Num3, Num0, WirelessSubwoofer, Video2,
--Confirm, DemoMode, Left, Num1, ShopRemoteControlForcedDynamic, FlashPlus, Display, Num6, GGuide, PartnerApp8, Prev, Num7, Num4, Play, Red,
--TopMenu, Num5, Analog2, DUX, Return, VolumeUp, DpadCenter, Options, Num12, PicOff, Rewind, iManual, DemoSurround, MediaAudioTrack, Up, TvPower,

  rc_codes = storage.get('RC_Codes') 
  if not rc_codes then
    rc_codes = Sony_get_remoteController_info()
  end

  IRCC_key_name = rc_codes[IRCC_name]
  Sony_Soap_request(Sony_ip, path_ircc, IRCC_key_name)
 
  if IRCC_name == "ChannelDown" or IRCC_name == "ChannelUp" then
    req_channel_delayed(0.5)
  end
end
 
function Sony_get_content_count()
  res = Sony_request(Sony_ip, path_avContent, encode_json_message("getContentCount", 11, {source = "tv:dvbt"}, "1.1"))
  return res.result[1].count
end

function Sony_get_content_list()
local num = Sony_get_content_count()
 
  res = Sony_request(Sony_ip, path_avContent, encode_json_message("getContentList", 88, {stIdx = 0, cnt = num, uri = "tv:dvbt"}, "1.5"))
  res = res.result[1]
  uri_s= {}
 
  for i = 1, #res do
    uri = res[i].uri
    title = res[i].title
    uri_s[title] = uri 
end
--- log(uri_s)
  storage.set('Chan_uri', uri_s)
  return uri_s
end

function Sony_Chanell(chan) -- chan is uri name and is returned by Sony_get_content_list() uncomment log(uri_s) above and call function Sony_get_content_list() to see what they are
  uri_C = storage.get('Chan_uri')
  if not uri_C then
     uri_C = Sony_get_content_count()
  end
  res = Sony_request(Sony_ip, path_avContent, encode_json_message("setPlayContent", 101, {uri = uri_C[chan]}, "1.0"))
  req_channel_delayed(0.2)
  return res
end
Reply


Forum Jump: