This release is a pre-release and may not be stable for production use.
pybravia-connect
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
ControlDeviceServicegRPC GetCapabilities/get_capabilities_jsonand capability helpersStartNotifyStatesdelta stream andget_statesExecCommandWithAuth(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_idandhmac_key(optionalkey_id,session_key) - Theatre systems default to port
55051(DEFAULT_THEATRE_PORT); TVs often needdiscover_grpc_port - Stop any Home Assistant
bravia_quadgRPC session on the same device before experimenting — dualkey_idsessions 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
- Run the command above. It prints an authorize URL (and opens it with
--open). Use an incognito/private window if the page is blank. - 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.
- Sign in with your Sony account for Home Entertainment & Sound Service.
- After login, the browser tries to open
ssh-app://signin?code=…. On desktop that fails — the redirect is not in the address bar. - In the Network panel, filter
signin→ copy thessh-app://signin?…Request URL or Location header, or just thecode=value. - 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
- CHANGELOG.md — release history
- SECURITY.md — reporting and operator guidance
- THREAT_MODEL.md — advisory scope
- Issues
- CONTRIBUTING.md — clone, lint, test, PRs
- AGENTS.md — contributor / agent conventions
- docs/development.md — protobuf stub regeneration
- docs/releasing.md — tagging and PyPI publish
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)
| File | Size | Uploaded | |
|---|---|---|---|
| pybravia_connect-0.1.0a12.tar.gz | 55.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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 logRelease 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