Posts: 8
Threads: 2
Joined: Jan 2020
Reputation:
2
17.02.2020, 09:58
(This post was last modified: 17.02.2020, 10:00 by arnocl.)
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
Posts: 7773
Threads: 42
Joined: Jun 2015
Reputation:
447
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)
Posts: 139
Threads: 44
Joined: Dec 2017
Reputation:
4
17.02.2020, 19:13
(This post was last modified: 17.02.2020, 23:40 by benanderson_475.)
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
Posts: 8
Threads: 2
Joined: Jan 2020
Reputation:
2
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.
Posts: 8
Threads: 2
Joined: Jan 2020
Reputation:
2
22.02.2020, 09:29
(This post was last modified: 22.02.2020, 09:39 by arnocl.)
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)
Posts: 139
Threads: 44
Joined: Dec 2017
Reputation:
4
23.09.2020, 03:45
(This post was last modified: 23.09.2020, 03:46 by benanderson_475.)
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
|