Bravia
An Elixir client for the local REST API on Sony BRAVIA televisions. Control picture settings, power, inputs, and audio over your network, with no cloud service involved.
{:ok, tv} = Bravia.new("192.168.1.20", psk: "0000")
{:ok, 15} = Bravia.Video.get_brightness(tv)
:ok = Bravia.Video.set_brightness(tv, 8)
Installation
def deps do
[{:bravia, "~> 0.1"}]
end
Enabling control on your television
Reading requires no setup. You can query a BRAVIA on your network immediately.
Changing anything requires a Pre-Shared Key, which you set on the television:
Settings → Network → Home Network → IP Control → Authentication → Normal and Pre-Shared Key
Choose a key there and pass it as :psk. Without one, writes fail with
%Bravia.Error{reason: :unauthorized} — by far the most common first-run problem.
Finding a television
{:ok, [device | _]} = Bravia.Discovery.discover()
device.friendly_name #=> "SONY XR-42A90K"
device.model #=> "XR-42A90K"
device.host #=> "192.168.1.20"
{:ok, tv} = Bravia.from_device(device, psk: "0000")
Discovery uses SSDP and follows whatever URL the television advertises, which is not a URL you can reliably construct yourself.
What you can control
# Picture
{:ok, targets} = Bravia.Video.get_picture_quality_settings(tv)
:ok = Bravia.Video.set_brightness(tv, 8)
:ok = Bravia.Video.set_picture_mode(tv, :game)
# Power
{:ok, :active} = Bravia.System.get_power_status(tv)
:ok = Bravia.System.set_power_saving_mode(tv, :picture_off)
# Inputs
{:ok, inputs} = Bravia.AvContent.get_current_external_inputs_status(tv)
:ok = Bravia.AvContent.set_play_content(tv, "extInput:hdmi?port=4")
# Audio
{:ok, outputs} = Bravia.Audio.get_volume_information(tv)
:ok = Bravia.Audio.set_volume(tv, 20)
:ok = Bravia.Audio.set_volume(tv, "+1")
Anything without a convenience function is still reachable:
Bravia.RPC.call(tv, "video", "getPictureQualitySettings", [%{"target" => ""}], "1.0")
Things the API will surprise you with
Picture settings are stored per input and per picture mode. A brightness change lands in whichever slot is active and stays there. Nothing puts it back — read the current value first if you intend to restore it.
Ranges are model-specific. This library does not hardcode them. Ask the set:
{:ok, [target]} = Bravia.Video.get_picture_quality_settings(tv, "brightness")
target["candidate"] #=> [%{"min" => 0, "max" => 50, "step" => 1}]
Method versions differ between models. The same television may offer
setAudioVolume at both "1.0" and "1.2". Check before assuming:
{:ok, capabilities} = Bravia.capabilities(tv)
capabilities["audio"]["setAudioVolume"] #=> ["1.0", "1.2"]
On OLED sets there is no backlight control.brightness is the panel luminance.
Scope
This is a stateless protocol client. It starts no processes and holds nothing between calls, so polling, caching, and supervision stay in your application where they belong.
Not included: IRCC remote key codes (a separate SOAP endpoint), app launching, and the cookie/PIN pairing flow. Pre-Shared Key authentication only.
Trying it against a real television
bin/bravia drives a set from the command line, so you can check behaviour without
writing any Elixir. It finds the television over SSDP, or set BRAVIA_HOST to skip
the search. Writes need BRAVIA_PSK.
$ bin/bravia status
power active
saving off
brightness 15
contrast 90
picture game
input HDMI 4 (PC)
volume speaker 0/100
$ bin/bravia inputs
HDMI 1 (Game) extInput:hdmi?port=1
HDMI 2 (Mister) extInput:hdmi?port=2
HDMI 3 (eARC/ARC) (Switch) extInput:hdmi?port=3
* HDMI 4 (PC) extInput:hdmi?port=4
AV extInput:composite?port=1
$ bin/bravia settings brightness
brightness 15 0..50
$ BRAVIA_PSK=0000 bin/bravia brightness 8
ok brightness -> 8
bin/bravia help lists every command, including a call escape hatch for methods
with no convenience function. For an interactive session, just console opens IEx
with tv bound to a client.
Testing
The suite runs against responses recorded from a real Sony XR-42A90K, so no hardware is needed:
just test # or: mix test
To include the tests that talk to a real television:
BRAVIA_HOST=192.168.1.20 just probe
Add BRAVIA_PSK to include the write test, which changes a picture setting and
restores it afterwards. Without a key it is skipped rather than failed.
Re-record the fixtures with BRAVIA_HOST=... just capture.
Development
just lists everything; the ones you will reach for:
| Recipe | What it does |
|---|---|
just test | offline suite against fixtures |
just probe | suite including live hardware tests |
just check | full gate: compile -Werror, format, credo, dialyzer, test |
just look | snapshot of the television's current state |
just discover | find Sony televisions on the network |
just console | IEx shell with tv bound |
just capture | re-record fixtures from a live set |
just document | build HTML docs |
just package | build the Hex tarball without publishing |
Licence
MIT.