Skip to content

Latest commit

 

History

History
229 lines (165 loc) · 8.25 KB

README.md

File metadata and controls

229 lines (165 loc) · 8.25 KB

tv-sony

Here is a tv command, for remote control of a television.

This uses the network interfaces provided by Sony Bravia TVs, from 2013 onwards. Support for other makes of TV is unknown, but I'm willing to take patches for anything "sufficiently similar".

This tool lets you control the TV from the command-line, and with a REPL, and with a curses mode to take keystrokes. That means:

  1. You can script control of the TV by just invoking a command to send instructions
  2. The Read-Eval-Print-Loop idiom is available; you have full readline history and editing, and context-aware tab-completion built in. The command can tab-complete its own commands, all remote control buttons known by the TV, and the names of various apps installed on the TV.
  3. You can use cursor keys (and/or vi keys) and space/enter for basic control without needing to type commands and hit enter. Or click on-screen buttons with your mouse.

It's written in Python, developed against Python 3.8.

Usage

$ tv --help
[ output of normal command-line flags ]
$ tv :help
[ lots of information about available commands]
$ tv on mute hdmi 4 volume 24 unmute

The tv command figures out that there are four commands there. Each one is sent to the TV half a second apart.

$ tv on mute key Down key Down key Right key Confirm unmute
$ tv on mute key [ Down Down Right Confirm ] unmute

Two ways of writing the same sequence: the key command takes one keyname to send, but if that key-name is [ then all parameters up until a matching ] (or the end) are taken to be keys to send.

$ tv
tv> :help
tv> key
tv key> Le<tab>
tv key> Left
tv key> Up Up Down Down Left Right Left Right Green Blue Confirm
tv key> <Ctrl-D>
tv> :keypad
 [remote-control here]
 q  (to quit)
tv> <Ctrl-D>
$

A flow where you enter the REPL and can use history navigation, tab completion, etc. After sending various key presses, we leave the remote button mode and instead ask for a keypad, where we can use cursor keys and space/enter to control things, before typing q to quit (as noted by the on-screen help), and then exiting.

(The list-of-keys mode speeds up slightly and only waits a quarter of a second between each key; these delays were chosen arbitrarily).

$ tv :keypad

Dive straight into the keypad control mode. The help will show you the available key-strokes, and there are pseudo-buttons show which you can click on, to be an in-tty GUI.

Setup

There are two options: one which involves the on-screen display of a PIN which you need to enter into the app, and one which is "Pre-Shared Key", in which you create effectively a password in the TV menus and supply the password to this app too.

On-Screen Display

This should normally be available; I've not gotten enough experience using this to confirm whether or not it's true that this will stop working after a few weeks. We store and update cookies so should be okay. But this support is very new.

$ tv --register `hostname -s` -H 192.168.1.2 -t myname

The parameter to --register is passed to the TV as the name of this client, so you should use the short name of the machine where tv is running. The TV should show an on-screen pop-up with a four-digit PIN code. If you see nothing, kill the tv process (Control-C) and try again.

Enter the PIN code into tv at the prompt.

You should be done.

Pre-Shared Key

You will need to enable this in the TV menus first.

Where this is in the menus changes with TV operating system updates. Loosely, head into the settings / cog, go to Network, and look for IP control and pre-shared setup. The TV may mention something about this being for A/V professionals.

When you set a pre-shared key, beware: the digits on your remote control do not enter ASCII digits: they enter some other set of Unicode digits. This can be a pain to debug. Use the on-screen keyboard to enter a key, instead of the remote control's digit buttons.

$ tv --host 192.168.1.2 --pin 1234 :write myname

A hostname can be used if you have working DNS at home, but otherwise you will need the TV's IP address. The parameter to :write becomes the name for this TV and will be automatically set as the default TV.

Installation

At present, this is a single script file. It has grown organically and is a bit unwieldy, but has the advantage that you can just copy it, mark it executable, and run it.

You will need two Python packages from outside of the standard library:

  1. requests : because it's the sanest way to manage HTTP in Python
  2. cryptography : because the TV implements a custom crypto system and we need to mess around at the hazmat layer to try to talk to it.

If anybody ever shows interest in this command and it starts to grow then I will probably split it into modules and make it pip installable. For now, you have the simple version which is from some idle time code tinkering.

Known Problems

Text Fields

I haven't yet managed to get text field reading and writing working.

My TV does not support HTTPS, and the way Sony get around the fact that some text fields might contain passwords, is to offer a custom encryption scheme. Please note: nothing here is my choice, I have no influence over what's required, I am trying to interoperate with a scheme designed by Sony.

The TV has an RSA-2048 key and the client generates keys for AES-128/CBC, updates the IV for each command, and encrypts the key:IV to the TV's RSA key and sends that along side text encrypted with the TV. A response will be encrypted with the same key (and it's not clear how the IV is changed, if at all, to prevent attacks from re-using the IV for send and reply).

I haven't gotten it working. But the code is still in there.

TV PIN/PSK Storage

I don't view this secret as particularly valuable, nor the secrets storage layer available on Linux as particularly useful (especially when compared to that offered by macOS), so the pre-shared key is stored unencrypted in a file on disk, ~/.config/tv/$TVNAME.pin

This might change but to the best of my knowledge, this secret can't do anything dangerous and does not warrant more complexity. If it leaks and is a problem then you can change the secret in your TV.

Technical Details

Unlike certain other companies, Sony provide online technical documentation for their APIs: https://pro-bravia.sony.net/develop/index.html.

This is excellent and in most places detailed and sufficient. This support for device owners and professionals to work with Sony is great to see.

There are three different APIs supported by the TV, and this command uses two of them. The remote control system is available while the TV is "turned off", as long as it has power, so the small sub-system for this is always-on.

There's a REST API, which allows for various queries, text-field manipulations, changing inputs and so forth.

And there's a SOAP XML API, "IRCC-IP", "InfraRed Compatible Control over Internet Protocol". This is how a remote control is emulated.

The complete list of remote control keys is provided by the TV and we cache it. We match in case-insensitive fashion. We only hardcode some alias names which will be tried if the TV does not provide a matching key name.

Some functions, such as changing the TV's input source, can be done with either API.

Files

The tv command is loosely XDG compliant. That is, we use the same defaults and the same environment controls, but we don't walk lists of paths, we just use the first path in any override environment variables.

Thus the default locations are:

  • ~/.config/tv/ : where we keep configuration. This includes the hostname and PIN, and which TV is the current default. You can also create a readline.conf file in that directory and it will be passed to the Python bindings to your system readline/libedit/whatever.
  • ~/.cache/tv/ : where we keep copies of data pulled from the TV (RSA keys, list of installed apps) and keep our readline history. Also UUIDs, cookies and other data associated with registration pairing.
  • ~/.local/share/tv/ : locally generated data which should persist is stored here; at present, that's client RSA keys, which are not (yet?) used.

Misc

The names "Sony" and "Bravia" are trademarks, used here descriptively without explicit permission.