A modern, robust Python library for controlling Sony Audio/Video Receivers (AVRs) and Soundbars that support the CIS-IP2 protocol over Ethernet/IP.
CIS stands for Custom Installation Services (or Solutions).
It's the Sony Specific protocol companies like Crestron, Control4 and homeseer use to provide their customers with local, granular control of their Sony AV devices. (At least that's what I could piece together based on misc forum posts)
sony-cispy provides a clean, async/await-based interface for communicating with Sony AVRs and soundbars using the CIS-IP2 protocol. This library merges the best aspects of previous implementations, offering:
- Universal API - Works with any CIS-IP2 compatible device
- Robust Connection Handling - Command ID tracking with futures for reliable request/response matching
- Real-time Notifications - Receive instant updates when device state changes
- Full Protocol Support - Access to the complete CIS-IP2 command set
- β¨ Universal API: Generic
get_feature()andset_feature()methods that work with any CIS-IP2 feature - π Robust Connection Handling: Command ID tracking with futures for reliable request/response matching
- π‘ Real-time Notifications: Register callbacks to receive real-time updates when device state changes
- π JSON Stream Decoding: Handles multiple JSON messages arriving in a single read
- β±οΈ Timeout Handling: Configurable timeouts for all network operations
- π Command Discovery: Access to the full CIS-IP2 command set via
commands_dict - π Modern Async/Await: Built with Python 3.13+ async/await patterns
- π§ͺ Well Tested: Comprehensive unit test suite with mocked network connections
The Sony CIS-IP2 protocol is a network (Ethernet/IP) command language for controlling Sony Audio/Video Receivers (AVRs), Soundbars and potentially other Sony AV devices. This protocol allows you to control volume, settings, and inputs over the network, rather than using older serial (RS-232) methods.
Important Notes:
- Sony does not officially refer to this as "CIS-IP2" in their documentation or device settings
- This protocol is typically enabled through settings like "External Control", "Simple IP Control" or "IP Control" in your AVR/soundbar's menu
- The exact setting name may vary by device model (e.g., "Network Control", "IP Remote", etc.)
Before using this library, you should verify that your device supports this protocol and that it's enabled. The easiest way to test compatibility is using netcat:
netcat <IP_ADDRESS> 33336
{"id":3, "type":"get","feature":"main.power"}Press Enter after typing the JSON command. You should receive a JSON response with the power state (e.g., {"id":3,"type":"result","feature":"main.power","value":"on"}).
If you don't get a response:
- Check that your device is on the same network
- Verify the IP address is correct
- Ensure IP/Network control is enabled in your device's settings
- Check that port 33336 is not blocked by a firewall
- Some devices may require specific firmware versions to support this protocol
# Clone the repository (or download and extract)
cd sony-cispy
# Install in development mode
pip install -e .Or install directly from a local path:
pip install -e /path/to/sony-cispy# Clone the repository (or download and extract)
cd sony-cispy
# Install development dependencies
pip install -r requirements-dev.txt
# Install in development mode
pip install -e .import asyncio
from sony_cispy import SonyCISIP2
async def main():
# Create client
client = SonyCISIP2(host="192.168.1.100", port=33336)
# Connect
await client.connect()
try:
# Get power state
power = await client.get_feature("main.power")
print(f"Power: {power}")
# Set volume
result = await client.set_feature("main.volumestep", 50)
print(f"Volume set: {result}")
# Get volume
volume = await client.get_feature("main.volumestep")
print(f"Current volume: {volume}")
finally:
# Disconnect
await client.disconnect()
asyncio.run(main())import asyncio
from sony_cispy import SonyCISIP2
async def main():
async with SonyCISIP2(host="192.168.1.100") as client:
power = await client.get_feature("main.power")
print(f"Power: {power}")
await client.set_feature("main.power", "on")
await client.set_feature("main.volumestep", 50)
asyncio.run(main())Register callbacks to receive real-time notifications when device state changes:
import asyncio
from sony_cispy import SonyCISIP2
async def on_power_change(feature, value):
print(f"β‘ Power changed to: {value}")
async def on_volume_change(feature, value):
print(f"π Volume changed to: {value}")
async def on_any_change(feature, value):
print(f"π’ {feature} changed to {value}")
async def main():
client = SonyCISIP2(host="192.168.1.100")
await client.connect()
try:
# Register callbacks
client.register_notification_callback("main.power", on_power_change)
client.register_notification_callback("main.volumestep", on_volume_change)
client.register_notification_callback(None, on_any_change) # All notifications
# Keep running to receive notifications
await asyncio.sleep(60)
finally:
await client.disconnect()
asyncio.run(main())Discover available CIS-IP2 commands programmatically:
from sony_cispy import commands_dict
# List all available commands
for feature, details in commands_dict.items():
print(f"{feature}: {details['description']}")
print(f" Set: {details['set']}, Get: {details['get']}, Notify: {details['notify']}")# Get power state
power = await client.get_feature("main.power") # Returns "on" or "off"
# Set power
await client.set_feature("main.power", "on")
await client.set_feature("main.power", "off")
await client.set_feature("main.power", "toggle")# Get/set volume (0-100)
volume = await client.get_feature("main.volumestep")
await client.set_feature("main.volumestep", 50)
# Get/set volume in dB (-92.0 to 23.0)
volume_db = await client.get_feature("main.volumedb")
await client.set_feature("main.volumedb", -20.0)
# Mute
mute = await client.get_feature("main.mute")
await client.set_feature("main.mute", "on")# Get current input
input_source = await client.get_feature("main.input")
# Set input (values vary by device)
await client.set_feature("main.input", "tv")
await client.set_feature("main.input", "hdmi1")
await client.set_feature("main.input", "spotify")# Sound field
await client.set_feature("audio.soundfield", "on")
# Voice enhancer
await client.set_feature("audio.voiceenhancer", "upon")- Python: 3.13 or higher
- Dependencies: None (uses only standard library)
- Library Documentation - Detailed API documentation
- Merge Summary - Details about the library merge
- Test Suite - Information about the test suite
- Examples - More usage examples
sony-cispy/
βββ sony_cispy/ # Main library package
β βββ __init__.py
β βββ client.py # SonyCISIP2 client class
β βββ constants.py # Protocol constants
β βββ commandset.py # Full CIS-IP2 command dictionary
β βββ variables.py # Variable placeholders
βββ tests/ # Unit tests
β βββ test_client.py
β βββ test_constants.py
β βββ ...
βββ example.py # Usage examples
βββ README.md # This file
# Install development dependencies
pip install -r requirements-dev.txt
# Run all tests
pytest
# Run with coverage
pytest --cov=sony_cispy --cov-report=html
# Run specific test file
pytest tests/test_client.py# Format code
black sony_cispy/ tests/
# Lint code
ruff check sony_cispy/ tests/
# Type checking
mypy sony_cispy/Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow PEP 8 style guidelines
- Add tests for new features
- Update documentation as needed
- Ensure all tests pass before submitting
This project is provided as-is. See individual source files for license information.
This library is not officially supported by Sony. Use at your own risk. The CIS-IP2 protocol may vary between device models, and not all commands may work with all devices.
This library was created by merging the best aspects of:
- The original
python_sonycisip2library's universal API - The
bravia-quad-homeassistantintegration's robust connection handling, with special thanks to @liudger for his code contributions!
See MERGE_SUMMARY.md for more details.
- π Bug Reports: Open an issue in the repository
- π‘ Feature Requests: Open an issue in the repository
- π Documentation: See the library documentation
- π¬ Questions: Open a discussion in the repository
Made with β€οΈ for the home automation and audio enthusiast community