Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

pybravia-connect

PyPI Python versions CI License

HA-agnostic Python client for Sony BRAVIA Connect local gRPC (ControlDeviceService).

This is a protocol library, not a Home Assistant integration. Integrations that speak BRAVIA Connect (for example bravia-quad-homeassistant and bravia-tv-grpc-homeassistant) can depend on this package once cut over.

Protocol code was extracted from those integrations (MIT). Thanks to @steamEngineer and @braviafanboy.

Status

Alpha (0.1.x on PyPI). APIs may change before 1.0. See CHANGELOG.md for release history. Apps that need a fixed surface can pin a specific version in their own lockfile.

Install

Requires Python 3.12+.

pip install pybravia-connect

bravia-connect and bravaconnect are reserved PyPI aliases for the same release (pip install bravia-connect or pip install bravaconnect installs pybravia-connect at the matching version). Prefer the canonical name above; the import package is always pybravia_connect.

For TV app-list and icon reads (AES-GCM decrypt):

pip install "pybravia-connect[crypto]"

For local development:

pip install -e ".[dev]"

Quickstart

Obtain credentials JSON first (see Credentials CLI). Stop any Home Assistant bravia_quad gRPC session on the same device before experimenting — dual key_id sessions flake.

from pybravia_connect import (
    BraviaConnectClient,
    DEFAULT_THEATRE_PORT,
    load_credentials,
)

HOST = "192.168.x.x"
CREDS_PATH = "/path/to/session_keys.json"  # never commit

creds = load_credentials(CREDS_PATH)
client = BraviaConnectClient(
    HOST,
    DEFAULT_THEATRE_PORT,  # or discover_grpc_port(HOST) for TVs
    creds["device_id"],
    creds["hmac_key"],
    key_id=creds.get("key_id"),
    session_key=creds.get("session_key"),
)
client.connect()
print(client.get_capabilities_json())
client.start_notify(lambda path, value: print(path, value))
# optional: client.get_states(["power", "volume"])
# optional write: client.exec_command("volume", 10)  # power on first
client.close()

Or run the read-only example (clone of this repo):

export BRAVIA_HOST=192.168.x.x
export BRAVIA_CREDENTIALS=/path/to/session_keys.json
python examples/read_capabilities.py

BraviaConnectClient is synchronous — run it in an executor from asyncio. The example is read-mostly; volume/mute writes no-op while the control unit is off. Public exports are listed in pybravia_connect.__all__.

Features

  • Connect and auth handshake for local ControlDeviceService gRPC
  • GetCapabilities / get_capabilities_json and capability helpers
  • StartNotifyStates delta stream and get_states
  • ExecCommandWithAuth (fresh session random per write)
  • OAuth / Seeds credential helpers (sync for scripts; async_* for HA)
  • TCP port discovery for non-Theatre devices (discover_grpc_port)
  • Optional TV AES-GCM app-list / icon reads (session_key + [crypto])

Validated on HT-A9M2 for connect/handshake, capabilities, notify, get_states, and volume writes while powered on.

Requirements

  • Device on a trusted private LAN (do not expose the gRPC port)
  • Credentials JSON with at least device_id and hmac_key (optional key_id, session_key)
  • Theatre systems default to port 55051 (DEFAULT_THEATRE_PORT); TVs often need discover_grpc_port
  • Stop any Home Assistant bravia_quad gRPC session on the same device before experimenting — dual key_id sessions flake

Credentials CLI

OAuth login writes a credentials JSON file for local gRPC. Never commit the output. After pip install pybravia-connect (from a release that includes the console script):

bravia-connect-keys --login --open -o /tmp/session_keys.json

Desktop OAuth walkthrough

  1. Run the command above. It prints an authorize URL (and opens it with --open). Use an incognito/private window if the page is blank.
  2. Before entering your username or password, open DevTools (Chrome/Firefox: F12 or Ctrl+Shift+I) → Network. Optionally enable Preserve log so the redirect is not cleared on navigation.
  3. Sign in with your Sony account for Home Entertainment & Sound Service.
  4. After login, the browser tries to open ssh-app://signin?code=…. On desktop that fails — the redirect is not in the address bar.
  5. In the Network panel, filter signin → copy the ssh-app://signin?… Request URL or Location header, or just the code= value.
  6. Paste that into the CLI prompt. With -o, the CLI writes the credentials JSON.

See bravia-connect-keys --help for --code, --token, --refresh, and --from-har. From a git checkout, python tools/get_session_keys.py remains a thin shim to the same entry point (useful before the console script is on PyPI, or for local muscle memory).

Credentials JSON shape

Required for local gRPC connect:

Field Role
device_id Seeds device id
hmac_key Local gRPC auth material

Often also present (optional for basic connect; used by some helpers):

Field Role
key_id Session key id
session_key Session key (e.g. TV AES-GCM paths with [crypto])

The CLI also writes OAuth fields (access_token, refresh_token, and related expiry helpers) so --refresh can mint new gRPC keys without a browser. Treat the whole file as a secret — see SECURITY.md.

Redacted example (placeholders only):

{
  "device_id": "<device-id>",
  "hmac_key": "<redacted>",
  "key_id": "<redacted>",
  "session_key": "<redacted>",
  "access_token": "<redacted>",
  "refresh_token": "<redacted>"
}

Documentation

Security

Local gRPC control assumes a trusted private LAN. Do not expose the device’s gRPC port to the internet. Never commit session-key JSON, OAuth tokens, or HAR files from the CLI tools.

See SECURITY.md for reporting and operator guidance, and THREAT_MODEL.md for what is in scope for private advisories.

Development

See CONTRIBUTING.md for the short contributor path.

python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
ruff check . && ruff format --check .
mypy
pytest -q

Live device smoke (tools/live_smoke.py; stop HA gRPC on the same device first):

Env Required Notes
BRAVIA_HOST yes Device IP
BRAVIA_CREDENTIALS yes Path to credentials JSON
BRAVIA_PORT no Default 55051
BRAVIA_SKIP_EXEC no Set 1 to skip writes
BRAVIA_EXEC_PATH no Field to write (default volume)
BRAVIA_EXEC_VALUE no Value to write (default toggles volume ±1)
export BRAVIA_HOST=192.168.x.x
export BRAVIA_CREDENTIALS=/path/to/keys.json
python tools/live_smoke.py

Open PRs against main and complete .github/PULL_REQUEST_TEMPLATE.md (tick exactly one change type so CI can label the PR for release notes). See AGENTS.md for agent/contributor conventions.

Protobuf regeneration and release steps: docs/development.md, docs/releasing.md.

License

MIT. Protocol code was extracted from the integrations listed above; thanks to @steamEngineer and @braviafanboy.

Metadata

Release files for pybravia-connect 0.1.0a12

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pybravia-connect 0.1.0a12
File Size Uploaded
pybravia_connect-0.1.0a12.tar.gz 55.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pybravia-connect 0.1.0a12
File Interpreter ABI Platform
pybravia_connect-0.1.0a12-py3-none-any.whl Python 3 none any Details

Total release size: 97.3 kB

Release files / pybravia_connect-0.1.0a12.tar.gz

Download URL pybravia_connect-0.1.0a12.tar.gz
Size 55.4 kB
Tags Source
SHA-256 checksum
How to use checksums
af4566b048a070935c90d6b92575493b61076719bdfdf88b9f823e92f35ee3ef
BLAKE2b-256 checksum
How to use checksums
f206cbbb0a755466d76b1467a447f2f585d1f689aadad827002c49cd301bc985
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 28, 2026.

Transparency log

Release files / pybravia_connect-0.1.0a12-py3-none-any.whl

Download URL pybravia_connect-0.1.0a12-py3-none-any.whl
Size 41.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1c2e0aa062d5c3b9ee8e56342854a7441ca923e8e0a3d59e0007b3a0e500c1fd
BLAKE2b-256 checksum
How to use checksums
e8cde4b8b48f57c13c15d0ea7c4c8f29df78203b3ef982311371bedd295209cb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 28, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page