Packages

A client for the Sony BRAVIA local REST API — picture settings, power, inputs, audio, and SSDP discovery.

Current section

Files

Jump to
bravia README.md
Raw

README.md

# 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.
```elixir
{: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
```elixir
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
```elixir
{: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
```elixir
# 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:
```elixir
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:
```elixir
{: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:
```elixir
{: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.