DEV Community

Cover image for Integrating my AVR with Home Assistant
MoniqueLive
MoniqueLive

Posted on

Integrating my AVR with Home Assistant

I was tired of digging through tiny on-device menus just to turn Zone 2 on and off on my AVR.

So I built a small Go CLI (zone2) that talks directly to the receiver over WebSocket, then wired it into Home Assistant as a command_line switch.

If you have an Arcam / AudioControl / JBL Synthesis receiver that exposes the setup WebSocket API on port 50001, this approach is straightforward and fast.

Source code

Why I chose a CLI first

Instead of jumping straight into a custom Home Assistant integration, I wanted a simple binary that:

  • can run anywhere
  • is easy to test from terminal
  • returns plain on / off output for automation parsing

That gave me a stable foundation before touching dashboards and YAML.

How the AVR communication works

The tool connects to:

  • ws://<AVR_IP>:50001

It sends binary protocol frames for Zone 2 (command 0x2F), then parses binary responses from the AVR.

Frame format (simplified):

request:  21 01 <command> <len> <payload...> 0D
response: 21 01 <command> <status> <len> <payload...> 0D
Enter fullscreen mode Exit fullscreen mode

For reads, it queries the Zone 2 model and inspects the second byte (model[1]) as power state:

  • 0 => off
  • 1 => on

For writes (on, off, toggle), it updates that byte and sends the full model back.

Reliability changes that mattered

The hard part was not "sending commands", it was making behavior reliable enough for automations.

I added a few guardrails:

  1. Frame splitting

    • Receivers can send multiple protocol frames in a single WebSocket message.
    • The client extracts valid frames by header/length/terminator and picks the right command.
  2. Strict response parsing

    • Validates framing, command ID, terminator, and declared payload length.
    • Rejects malformed frames early.
  3. Retry on transient states

    • Zone 2 query retries up to 5 times.
    • Handles temporary 0x85 status by waiting briefly and retrying.
  4. Post-write verification loop

    • After a write, it re-queries state until the target sticks (default 20 attempts).
    • This avoids false positives where a write ACK arrives but state does not actually change.

This is what made it usable from Home Assistant without random "it worked... I think?" moments.

CLI usage

./zone2-macos-arm64 -host YOUR_AVR_IP -mode status
./zone2-macos-arm64 -host YOUR_AVR_IP -mode on
./zone2-macos-arm64 -host YOUR_AVR_IP -mode off
./zone2-macos-arm64 -host YOUR_AVR_IP -mode toggle
Enter fullscreen mode Exit fullscreen mode

Flags:

  • -host (required)
  • -mode (on|off|toggle|status)
  • -timeout (default 4s)
  • -verify (default 20, used for writes)
  • -verbose (prints raw TX/RX frames)

Home Assistant integration

I cross-compile a Linux ARM64 binary for HA OS (Raspberry Pi 5), copy it into /config/bin, and expose it via command_line:

command_line:
  - switch:
      name: AVR Zone 2
      unique_id: avr_zone2
      command_on: "/config/bin/zone2 -host YOUR_AVR_IP -mode on -timeout 4s -verify 20"
      command_off: "/config/bin/zone2 -host YOUR_AVR_IP -mode off -timeout 4s -verify 20"
      command_state: "/config/bin/zone2 -host YOUR_AVR_IP -mode status -timeout 4s"
      value_template: "{{ value | trim | lower == 'on' }}"
      scan_interval: 10
Enter fullscreen mode Exit fullscreen mode

Because the CLI prints exactly on or off, the value template stays simple and reliable.

Build + release flow

The repo includes:

  • Makefile targets for Linux ARM64 + macOS binaries
  • CI (go test, go vet)
  • tag-triggered GitHub release workflow attaching compiled binaries

That made it easy to test locally and deploy repeatably.

Final thoughts

This was a small project, but a useful reminder: in home automation, state verification is more important than "command sent successfully".

A tiny, deterministic CLI with clear output is often enough to bridge unsupported hardware into Home Assistant cleanly.

If I extend this next, I'll likely add controls for input/volume and package a full HA integration once the protocol surface is mature.

Top comments (0)