A Home Assistant custom integration for controlling Sony Bravia Theatre home theater systems via TCP/IP.
This integration may also be compatible with other Bravia audio devices - see the Device Compatibility section for details.
- Auto-Discovery: Automatically discovers Bravia Theatre devices on your network using mDNS/zeroconf - no manual IP configuration needed
- Power Control: Turn your Bravia Theatre system on and off
- Volume Control: Adjust main volume from 0-100 via a number entity
- Rear Level Control: Adjust rear speaker level from -10-10 via a number entity
- Source Selection: Switch between inputs (TV/eARC, HDMI In, Spotify, Bluetooth, Airplay)
- Bass Level Control: Automatically adapts based on subwoofer presence:
- With subwoofer: Slider from -10 to +10
- Without subwoofer: Select between MIN, MID, MAX
- Subwoofer Auto-Detection: Automatically detects if a subwoofer is connected and adjusts bass level controls accordingly
- Voice Enhancer: Toggle voice enhancer on/off
- Sound Field: Toggle sound field processing on/off
- Night Mode: Toggle night mode on/off
- HDMI CEC: Toggle HDMI CEC on/off
- Auto Standby: Toggle automatic standby behavior on/off
- Dynamic Range Compressor (DRC): Control Dynamic Range Compressor mode (Auto, On, Off) - polls for state changes
- Auto Volume: Toggle Auto Volume on/off - polls for state changes
- Real-time Updates: Automatically receives and processes notifications from the device for all state changes (where supported)
- Device Integration: All entities are properly nested under a single device in Home Assistant
The following table details device compatibility with this Home Assistant integration. Compatibility is based on whether devices use the same TCP/IP protocol (port 33336) as the BRAVIA Theatre Theatre.
| Device Name | Model | Connection Type | Compatibility |
|---|---|---|---|
| BRAVIA Theatre Quad | HT-A9M2 | WiFi | Compatible |
| BRAVIA Theatre Bar 8 | HT-A8000 | WiFi | Untested |
| BRAVIA Theatre Bar 9 | HT-A9000 | WiFi | Untested |
| BRAVIA Theatre Bar 6 | HT-B600/BD60 | Bluetooth | Incompatible |
| BRAVIA Theatre System 6 | HT-S60 | Bluetooth | Incompatible |
| HT-AX7 | HT-AX7 | Bluetooth | Incompatible |
| HT-S2000 | HT-S2000 | Bluetooth | Incompatible |
Note: Devices marked as "Untested" may be compatible if they use the same TCP/IP control protocol. Compatibility testing and feedback from users with these devices is welcome!. For a complete list of Sony Sound Bars & Home Theatre Systems, see the Sony Support Article.
Before setting up this integration, ensure External control is enabled on your Bravia device:
- Open the Sony Home Entertainment Connect app on your phone
- Go to Settings → Network settings
- Enable External control
⚠️ Without this setting enabled, the integration will not be able to communicate with your device.
- Ensure HACS is installed
- Go to HACS → Integrations
- Search for "Bravia Theatre" and install it
- Restart Home Assistant
-
Copy the
bravia_quadfolder to your Home Assistantcustom_componentsdirectory:<config>/custom_components/bravia_quad/ -
Restart Home Assistant
-
Go to Settings → Devices & Services → Add Integration
-
Search for "Bravia Theatre" and follow the setup wizard
The integration supports automatic discovery of Bravia Theatre devices on your local network using mDNS/zeroconf. When you add the integration, Home Assistant will automatically detect any Bravia Theatre devices and prompt you to configure them.
If your device is not automatically discovered, you can add it manually by:
- Selecting "Bravia Theatre" from the integration list
- Choosing "Configure" or "Submit" when prompted
- Entering the device's IP address manually
- Optionally providing a friendly name (defaults to "Bravia Theatre")
During setup, you will be prompted to provide:
- IP Address: The IP address of your Bravia Theatre device (required if not auto-discovered)
- Name (optional): A friendly name for the device (defaults to "Bravia Theatre")
The integration will automatically test the connection by sending a power status request. Make sure:
- IP control is enabled on your Bravia Theatre device
- The device is accessible on your network
- Port 33336 is not blocked by a firewall
The integration creates the following entities under your Bravia Theatre device:
| Entity | Type | Description | Range/Options |
|---|---|---|---|
switch.bravia_quad_*_power |
Switch | Control power on/off | on/off |
number.bravia_quad_*_volume |
Number | Control main volume | 0-100 |
number.bravia_quad_*_rear_level |
Number | Control rear speaker level | -10-10 |
number.bravia_quad_*_bass_level |
Number | Control bass level (with subwoofer) | -10-10 |
select.bravia_quad_*_bass_level |
Select | Control bass level (without subwoofer) | MIN, MID, MAX |
select.bravia_quad_*_source |
Select | Select input source | TV (eARC), HDMI In, Spotify, Bluetooth, Airplay |
switch.bravia_quad_*_voice_enhancer |
Switch | Toggle voice enhancer | on/off |
switch.bravia_quad_*_sound_field |
Switch | Toggle sound field processing | on/off |
switch.bravia_quad_*_night_mode |
Switch | Toggle night mode | on/off |
switch.bravia_quad_*_hdmi_cec |
Switch | Toggle HDMI CEC | on/off |
switch.bravia_quad_*_auto_standby |
Switch | Toggle auto standby | on/off |
select.bravia_quad_*_drc |
Select | Dynamic Range Compressor (DRC) | Auto, On, Off |
switch.bravia_quad_*_advanced_auto_volume |
Switch | Auto Volume | on/off |
button.bravia_quad_*_detect_subwoofer |
Button | Re-detect subwoofer (diagnostic) | - |
button.bravia_quad_*_bluetooth_pairing |
Button | Trigger Bluetooth pairing mode (diagnostic) | - |
Note: * represents your device's unique entry ID
Note: Only one bass level entity will be created based on whether a subwoofer is detected.
The integration communicates with the Bravia Theatre device via TCP on port 33336 using JSON messages:
Get Request:
{"id": 3, "type": "get", "feature": "main.power"}Get Response:
{"feature": "main.power", "id": 3, "type": "result", "value": "off"}Set Request:
{"id": 3, "type": "set", "feature": "main.power", "value": "on"}Set Response:
{"id": 3, "type": "result", "value": "ACK"}When maintaining an open connection, the device sends real-time notifications for all state changes:
{"feature": "main.power", "type": "notify", "value": "on"}
{"feature": "main.volumestep", "type": "notify", "value": "21"}
{"feature": "main.input", "type": "notify", "value": "spotify"}
{"feature": "main.rearvolumestep", "type": "notify", "value": "5"}
{"feature": "main.bassstep", "type": "notify", "value": "1"}
{"feature": "audio.voiceenhancer", "type": "notify", "value": "upon"}
{"feature": "audio.soundfield", "type": "notify", "value": "on"}
{"feature": "audio.nightmode", "type": "notify", "value": "off"}
{"feature": "hdmi.cec", "type": "notify", "value": "on"}
{"feature": "system.autostandby", "type": "notify", "value": "off"}- Get Power State:
{"id": 3, "type": "get", "feature": "main.power"} - Set Power On:
{"id": 3, "type": "set", "feature": "main.power", "value": "on"} - Set Power Off:
{"id": 3, "type": "set", "feature": "main.power", "value": "off"}
- Get Volume:
{"id": 2, "type": "get", "feature": "main.volumestep"} - Set Volume:
{"id": 2, "type": "set", "feature": "main.volumestep", "value": 50}(0-100)
- Get Rear Level:
{"id": 2, "type": "get", "feature": "main.rearvolumestep"} - Set Rear Level:
{"id": 2, "type": "set", "feature": "main.rearvolumestep", "value": 5}(-10 to 10)
- Get Source:
{"id": 2, "type": "get", "feature": "main.input"} - Set Source:
{"id": 2, "type": "set", "feature": "main.input", "value": "tv"}
Available Sources:
tv- TV (eARC)hdmi1- HDMI Inspotify- Spotifybluetooth- Bluetoothairplay2- Airplay (Note: Can be detected when active, but cannot be set via command - only activated when an Airplay device casts to the Bravia)
The bass level range depends on whether a subwoofer is connected:
With Subwoofer:
- Get Bass Level:
{"id": 2, "type": "get", "feature": "main.bassstep"} - Set Bass Level:
{"id": 2, "type": "set", "feature": "main.bassstep", "value": 5}(-10 to 10)
Without Subwoofer:
- Get Bass Level:
{"id": 2, "type": "get", "feature": "main.bassstep"} - Set Bass Level:
{"id": 2, "type": "set", "feature": "main.bassstep", "value": 1}(0=MIN, 1=MID, 2=MAX)
- Get Voice Enhancer:
{"id": 1, "type": "get", "feature": "audio.voiceenhancer"} - Set Voice Enhancer On:
{"id": 1, "type": "set", "feature": "audio.voiceenhancer", "value": "upon"} - Set Voice Enhancer Off:
{"id": 1, "type": "set", "feature": "audio.voiceenhancer", "value": "upoff"}
- Get Sound Field:
{"id": 1, "type": "get", "feature": "audio.soundfield"} - Set Sound Field On:
{"id": 1, "type": "set", "feature": "audio.soundfield", "value": "on"} - Set Sound Field Off:
{"id": 1, "type": "set", "feature": "audio.soundfield", "value": "off"}
- Get Night Mode:
{"id": 1, "type": "get", "feature": "audio.nightmode"} - Set Night Mode On:
{"id": 1, "type": "set", "feature": "audio.nightmode", "value": "on"} - Set Night Mode Off:
{"id": 1, "type": "set", "feature": "audio.nightmode", "value": "off"}
- Get HDMI CEC:
{"id": 1, "type": "get", "feature": "hdmi.cec"} - Set HDMI CEC On:
{"id": 1, "type": "set", "feature": "hdmi.cec", "value": "on"} - Set HDMI CEC Off:
{"id": 1, "type": "set", "feature": "hdmi.cec", "value": "off"}
- Get Auto Standby:
{"id": 1, "type": "get", "feature": "system.autostandby"} - Set Auto Standby On:
{"id": 1, "type": "set", "feature": "system.autostandby", "value": "on"} - Set Auto Standby Off:
{"id": 1, "type": "set", "feature": "system.autostandby", "value": "off"}
- Get DRC:
{"id": 1, "type": "get", "feature": "audio.drangecomp"} - Set DRC Auto:
{"id": 1, "type": "set", "feature": "audio.drangecomp", "value": "auto"} - Set DRC On:
{"id": 1, "type": "set", "feature": "audio.drangecomp", "value": "on"} - Set DRC Off:
{"id": 1, "type": "set", "feature": "audio.drangecomp", "value": "off"}
Note: The DRC entity uses polling to update its state, as the device does not send notifications for this feature.
- Get AAV:
{"id": 1, "type": "get", "feature": "audio.aav"} - Set AAV On:
{"id": 1, "type": "set", "feature": "audio.aav", "value": "on"} - Set AAV Off:
{"id": 1, "type": "set", "feature": "audio.aav", "value": "off"}
Note: The Auto Volume entity uses polling to update its state, as the device does not send notifications for this feature.
Per Sony docs on the feature, Auto Volume should be disabled when listening to music.
If you encounter connection problems:
- Verify IP Address: Ensure the IP address is correct and the device is on the same network
- Check IP Control: Verify that IP control is enabled on your Bravia Theatre device
- Firewall: Ensure port 33336 is not blocked by your firewall
- Test Connection: Test the connection manually using netcat:
You should receive a JSON response with the power state.
netcat <IP_ADDRESS> 33336 {"id":3, "type":"get","feature":"main.power"}
- Check the Home Assistant logs for any error messages
- Ensure the notification listener is running (check logs for "Starting notification listener")
- Try reloading the integration: Settings → Devices & Services → Bravia Theatre → Reload
- The integration polls for initial values on startup
- If values don't update, check that the device is responding to get commands
- Notifications will update values in real-time when changes occur
The easiest way to develop and test this integration is using the included DevContainer configuration with Visual Studio Code.
- Make sure you have Visual Studio Code and the Dev Containers extension installed.
- Clone this repository.
- Open the repository in VS Code and click "Reopen in Container" when prompted (or use the command palette:
Dev Containers: Reopen in Container). - Once the container is ready, run
scripts/developto start Home Assistant with the integration loaded. - Access Home Assistant at http://localhost:8123.
The devcontainer supports two network modes that can be switched using VS Code tasks:
- Isolated network: Container runs on Docker's default bridge network
- Port forwarding: Ports are forwarded from container to host
- Use case: General development, when mDNS/zeroconf discovery is not needed
- Shared network: Container shares the host's network stack directly
- Direct access: Container can access host network interfaces and services
- Use case: Required for mDNS/zeroconf discovery - allows the container to receive multicast DNS traffic from devices on your local network
Why Host Mode for mDNS/Zeroconf?
mDNS (multicast DNS) and zeroconf discovery rely on Layer 2 network traffic (multicast packets). When using bridge networking (the docker default), these multicast packets are isolated from the Docker network and cannot reach the container. Host networking allows the container to directly access the host's network interfaces, enabling it to receive and respond to mDNS broadcasts from devices like the Bravia Theatre system.
Switching Network Modes:
- Open the Command Palette (Ctrl+Shift+P / Cmd+Shift+P)
- Type "Tasks: Run Task"
- Select either:
- "Devcontainer: Set Host Network Mode" - For mDNS/zeroconf development
- "Devcontainer: Set Bridge Network Mode" - For default isolated networking
- Rebuild the devcontainer for changes to take effect:
- Command Palette → "Dev Containers: Rebuild Container"
⚠️ Important for Docker Desktop Users:If you encounter errors when switching to host mode, you may need to enable host networking in Docker Desktop first:
- Sign in to your Docker account in Docker Desktop
- Navigate to Settings
- Under the Resources tab, select Network
- Check the Enable host networking option
- Select Apply and restart
See the Docker Desktop host networking documentation for more details.
Note: Host networking requires Docker Desktop version 4.34 or later and only works with Linux containers. It also doesn't work with Enhanced Container Isolation enabled.
| Script | Description |
|---|---|
scripts/setup |
Sets up development environment with uv (installs dependencies + pre-commit hooks) |
scripts/develop |
Starts Home Assistant with the integration in debug mode |
scripts/lint |
Runs Ruff to format and lint the code |
This project uses uv for dependency management.
# Install dependencies and set up pre-commit hooks
./scripts/setup
# Or manually with uv
uv sync --dev
# Run tests
uv run pytest
# Run Home Assistant in debug mode
./scripts/developcustom_components/bravia_quad/
├── __init__.py # Integration setup
├── __version__.py # Version information
├── manifest.json # Integration metadata
├── config_flow.py # Configuration flow
├── bravia_quad_client.py # TCP client for device communication
├── switch.py # Power switch entity
├── number.py # Volume number entity
├── select.py # Source select entity
├── const.py # Constants
└── strings.json # UI strings
This project uses Ruff for linting and code formatting. The configuration follows Home Assistant's coding standards:
- Linting: Automated linting runs on all pull requests via GitHub Actions
- Formatting: Code is automatically formatted using Ruff
- Python Version: Targets Python 3.13.2+
Run linting locally:
./scripts/lintThe project includes a comprehensive test suite using pytest:
# Run all tests
uv run pytest
# Run tests with verbose output
uv run pytest -v
# Run tests with coverage
uv run pytest --cov=custom_components/bravia_quadThis project uses GitHub Actions for continuous integration and deployment:
- Hassfest: Validates the integration manifest and ensures compliance with Home Assistant standards
- Lint: Runs Ruff to check code quality and formatting on all pull requests
- Tests: Runs the pytest test suite on all pull requests
- Release: Automated release workflow that:
- Validates version format
- Updates version in
pyproject.tomlandmanifest.json - Creates Git tags
- Generates GitHub releases
Dependencies are automatically kept up to date via Renovate for:
- GitHub Actions
- Python packages (via pyproject.toml)
To test the connection manually:
# Using netcat
netcat <IP_ADDRESS> 33336
{"id":3, "type":"get","feature":"main.power"}Or using Python:
import socket
import json
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('YOUR_IP', 33336))
s.send(b'{"id":3, "type":"get","feature":"main.power"}\n')
response = s.recv(1024).decode()
print(json.loads(response))
s.close()Contributions are welcome! Please feel free to submit a Pull Request.
- Code Style: Follow the existing code style and use Ruff for formatting
- Testing: Test your changes thoroughly before submitting
- Pull Requests:
- Ensure all CI checks pass (Hassfest, Lint)
- Update documentation if needed
- Follow conventional commit messages when possible
- Issues: If you find a bug or have a feature request, please open an issue first to discuss
This integration is provided as-is under the MIT License.
This integration is not officially supported by Sony. Use at your own risk.
For issues, questions, or feature requests, please open an issue on GitHub.
Made with ❤️ for the Home Assistant community
