yamaha-py
yamaha-py talks directly to your Yamaha AV receiver over the local network — no cloud, no Yamaha account, no internet required.
Features
- Pure local control — two protocols: YNCA over TCP (port 50000) and HTTP XML (Yamaha Remote Control API)
- Rich CLI — human-readable output or
--jsonfor scripting and pipes - Multi-profile config — manage multiple receivers, each with host, protocol, zone, timeout, and retries
- Zone support — control
mainandzone2independently - Net Radio — stream URLs via UPnP; manage presets per profile
- Tuner — FM/AM band, frequency, RDS, presets
- Receiver discovery — parallel
/24subnet scan with optional profile save - Stable exit codes — every error maps to a predictable shell exit code
Installation
pip install yamactl
# or with uv
uv add yamactl
Requires Python 3.14+.
[!NOTE] For mDNS discovery, install the optional dependency:
pip install "yamactl[discovery]"
Quick start
1. Create a profile
yamactl config init --name livingroom --host 192.168.178.42 --protocol ynca
2. Check the receiver
yamactl status
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Receiver Status ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ Host 192.168.178.42 │
│ Model RX-V475 │
│ Power on │
│ Input HDMI1 │
│ Volume -45.0 dB │
│ Mute off │
│ DSP 5ch Stereo │
└────────────────────────────────┘
3. Control it
yamactl power on
yamactl volume set -- -40
yamactl volume up --steps 4
yamactl input set HDMI2
yamactl mute toggle
yamactl scene load 1
Python SDK
YamaCtlClient is the public API — use it to integrate receiver control into your own scripts or applications.
from yamactl.client import YamaCtlClient
# Uses the default profile from ~/.config/yamaha-local/config.yaml
with YamaCtlClient.from_profile() as client:
# Read status
status = client.get_status()
print(status.power, status.input, status.volume_db)
# Power & volume
client.set_power("on")
client.set_volume(-35.0)
client.volume_up(steps=2) # +1.0 dB
# Mute
client.set_mute(False)
new_state = client.toggle_mute()
# Input & DSP
client.set_input("HDMI1")
client.set_dsp_mode("5ch Stereo")
client.load_scene(1)
# Tuner
client.set_tuner_band("FM")
client.set_tuner_fm_freq(89.5)
# Net Radio
client.play_netradio_url(
"http://wdr-wdr3-live.icecastssl.wdr.de/wdr/wdr3/live/128/stream.mp3",
title="WDR3",
)
Use a named profile or override the zone:
with YamaCtlClient.from_profile(profile="bedroom", zone_override="zone2") as client:
client.set_volume(-40.0)
All methods raise subclasses of YamaCtlError on failure (see Exit codes for the mapping).
CLI reference
yamactl [--profile NAME] [--zone main|zone2] [--json]
Status & discovery
| Command | Description |
|---|---|
yamactl status |
Full receiver status |
yamactl discover --subnet 192.168.178.0/24 |
Scan subnet for Yamaha receivers |
Power
| Command | Description |
|---|---|
yamactl power on |
Power on |
yamactl power standby |
Standby |
yamactl power toggle |
Toggle power state |
Volume
| Command | Description |
|---|---|
yamactl volume get |
Get current volume in dB |
yamactl volume set <dB> |
Set absolute volume (use -- -48 for negative) |
yamactl volume up [--steps N] |
Increase by N × 0.5 dB |
yamactl volume down [--steps N] |
Decrease by N × 0.5 dB |
Mute
| Command | Description |
|---|---|
yamactl mute on |
Enable mute |
yamactl mute off |
Disable mute |
yamactl mute toggle |
Toggle mute state |
Input & sound
| Command | Description |
|---|---|
yamactl input set <source> |
Switch input (HDMI1, AV1, NET RADIO, …) |
yamactl input list |
List available inputs |
yamactl sound dsp <mode> |
Set DSP / surround mode |
yamactl sound straight on|off |
Straight mode |
yamactl sound sleep <minutes> |
Sleep timer (or off) |
Tuner
| Command | Description |
|---|---|
yamactl tuner status |
Band, frequency, RDS |
yamactl tuner band fm|am |
Switch band |
yamactl tuner fm <MHz> |
Set FM frequency in MHz (e.g. 87.50) |
yamactl tuner am <kHz> |
Set AM frequency in kHz (e.g. 810) |
yamactl tuner preset <N> |
Load preset |
Net Radio
| Command | Description |
|---|---|
yamactl netradio status |
Now-playing info |
yamactl netradio play <name> |
Play a saved URL preset |
yamactl netradio stop |
Stop playback |
yamactl netradio url add <name> <url> |
Save a streaming URL preset |
yamactl netradio url list |
List saved URL presets |
yamactl netradio url remove <name> |
Remove a URL preset |
Config management
| Command | Description |
|---|---|
yamactl config init --name NAME --host IP |
Create or update a profile |
yamactl config show |
Show all profiles |
yamactl config set-default --name NAME |
Change default profile |
Diagnostics
| Command | Description |
|---|---|
yamactl raw ynca "@MAIN:VOL=?" |
Send raw YNCA command |
yamactl raw xml "<YAMAHA_AV ...>" |
Send raw HTTP XML envelope |
Use --json for machine-readable output on any read command. All log output goes to stderr; stdout stays scriptable.
Exit codes
| Code | Error |
|---|---|
0 |
success |
2 |
config / usage error |
10 |
receiver unreachable |
11 |
receiver busy (YNCA port in use) |
12 |
command timeout |
20 |
invalid input source |
21 |
operation unsupported by protocol |
30 |
unexpected receiver response |
MCP Server
yamaha-py ships a Model Context Protocol server that exposes all receiver controls as MCP tools, usable from any MCP-compatible AI client (Claude Desktop, Cursor, VS Code Copilot, etc.).
yamactl-mcp # stdio transport — wire this up as an MCP server
Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"yamactl": {
"command": "yamactl-mcp"
}
}
}
VS Code Copilot (.vscode/mcp.json)
{
"servers": {
"yamactl": {
"command": "uv",
"args": ["run", "yamactl-mcp"]
}
}
}
Available MCP tools
| Tool | Description |
|---|---|
get_receiver_status |
Full status (power, input, volume, mute, DSP) |
set_power |
Power on / standby |
get_volume / set_volume |
Read or set volume in dB |
volume_up / volume_down |
Step volume up or down (0.5 dB/step) |
get_mute / set_mute / toggle_mute |
Mute control |
list_inputs / set_input |
Input source selection |
load_scene |
Load a Yamaha scene preset (1–4) |
get_tuner_status |
Tuner band, frequency, preset, RDS |
set_tuner_band / set_tuner_fm_freq / set_tuner_am_freq / set_tuner_preset |
Tuner control |
get_netradio_status |
Now-playing info |
play_netradio_url / pause_netradio / stop_netradio |
Net radio / streaming playback |
The server uses the default configured profile (~/.config/yamaha-local/config.yaml).
Protocols
yamaha-py supports two protocol adapters, selectable per profile:
| Protocol | --protocol |
Port | Notes |
|---|---|---|---|
| YNCA (default) | ynca |
50000 (TCP) | Full bidirectional control via the ynca library |
| HTTP XML | http_xml |
80 (HTTP) | Yamaha Remote Control API; no extra dependency |
[!TIP] YNCA gives richer status feedback and is the recommended choice. Use
http_xmlif YNCA port 50000 is blocked on your network.
Configuration
Config file: ~/.config/yamaha-local/config.yaml
default_profile: livingroom
profiles:
livingroom:
host: 192.168.178.42
protocol: ynca
zone: main
timeout_seconds: 3.0
retries: 1
netradio_presets:
wdr3: "http://wdr-wdr3-live.icecastssl.wdr.de/wdr/wdr3/live/128/stream.mp3"
swr2: "http://swr-swr2-live.icecast.t-systems.de/swr/swr2/live/128/stream.mp3"
Precedence: --profile flag > default_profile > first profile in file.
Development
git clone https://github.com/jenreh/yamaha-py
cd yamaha-py
uv sync
task test # pytest with coverage
task lint # ruff
task format # ruff format
[!NOTE] Real-device integration tests require a reachable receiver. Set
YAMACTL_TEST_HOST=<IP>and runpytest -m rxv475.
Metadata
Release files for yamactl 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| yamactl-0.3.0.tar.gz | 29.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| yamactl-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 71.2 kB
Release files / yamactl-0.3.0.tar.gz
| Download URL | yamactl-0.3.0.tar.gz |
|---|---|
| Size | 29.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d97877c9a72a48b1e95b615edd3dad7be3174765eff4c821f52a680fafdcacc3
|
|
BLAKE2b-256 checksum How to use checksums |
7de4de11eca9e4ed44400fc41d2074dbb588595ebed1b8a1c99a225e92b4afa1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / yamactl-0.3.0-py3-none-any.whl
| Download URL | yamactl-0.3.0-py3-none-any.whl |
|---|---|
| Size | 41.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e22e4c7ec9e71fc8180c0cafeaa094e68e95970afe448610b3ee1875b26fa035
|
|
BLAKE2b-256 checksum How to use checksums |
4173f24b599c93e72823ec34cfd734b32288a9524bd4c288432e3edbf25a6610
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|