Skip to main content

AudioControl Multi-Zone Amplifier

The audiocontrol driver controls AudioControl networked multi-zone matrix amplifiers (Director M-series, D2800, D4600). Telnet ASCII commands on port 23 drive the amp and poll zone status via SYSTEMstat?.

Prerequisites

  • Amplifier on the same LAN as GEM, with a static IP or DHCP reservation.
note

The /json/signalprocessing.json endpoint is only used once at connect for model detection — its body is too large for the device HTTP server to serve reliably on multi-zone amps (truncates around 24 KB), so all live zone state comes over telnet.

Setup

  1. System → Devices: add a device with driver audiocontrol. Set ip. Default port is 23.
  2. Save and enable. On connect the driver:
    • probes /json/signalprocessing.json for ampModel / ampName and writes them to model / amp_name. If the JSON endpoint is unreachable it falls back to SYSTEMstat? over telnet, parsing the AMPLIFIER NAME: line.
    • starts polling the amp every sync_interval ms (default 5000) via SYSTEMstat?. Each powered zone row in the response auto-creates a GEM zone the first time it is seen, under the av subsystem, with a numeric address (1..N). Digital Out rows are polled but never auto-created — see below.
Digital Outs are not auto-created

A Digital Out usually isn't a room of its own — it feeds a whole-house source to a zone that has its own local receiver doing the amplification. Creating a zone for it would just add an output nobody controls to the zone list, so only the powered outputs are created.

If a site genuinely does control a Digital Out directly, add the zone by hand (System → Zones, device = the amp, address a or b) and the driver will sync its state like any other. Digital Out zones created by earlier versions are left alone and keep updating — nothing is removed on upgrade.

Zone names when the label is already taken

Zone names are unique system-wide, but amp labels are not — two outputs can both be called "Main Patio", and the formatted name may already belong to a zone on another device. Auto-create handles the collision instead of failing:

  • If the name is free, the zone is created as <device>_<label>.
  • If the name belongs to an unrelated zone, the address is appended (<device>_<label>_3). The zone's label still shows the amp's human name.
  • If the row that owns the name is this amp's own zone at this address (for example a zone under a disabled subsystem, so it isn't loaded), the zone is left alone — it is never recreated or driven. Re-enable the subsystem and reload the device to pick it back up.

An address whose create fails is retried on a 10-minute backoff rather than on every poll, so a permanent collision doesn't flood the log. This is the shared behavior for every driver that discovers its own zones — see auto-created zones.

  1. You don't have to wait for the first poll — run the sync_zones command to force an immediate SYSTEMstat? sweep and create any missing zones now. It reports how many zones it created versus how many already existing.
  2. Run sync_av_zones to create matching AV Zone rows for the main (numeric) zone outputs (so each shows up in the AV routing graph). Existing AV Zone rows are left alone. Digital Out zones are skipped — they're driven by the DXO commands rather than Z[address] templates, and their always-on power state would otherwise trip AV power divergence detection. If a Digital Out already has an AV Zone row from an earlier sync, delete it (or set power_reconcile = false on the zone) to stop divergence alerts.

Attributes

Device — required

AttributeTypeDescription
ipstringLAN IP of the amplifier.

Device — optional

AttributeTypeDefaultDescription
portint23Telnet port.
zone_countint8Number of output zones.
sync_intervalint (ms)5000Zone status poll cadence.

Reflected device attributes

AttributeSource
modelampModel from one-shot JSON probe, or AMPLIFIER NAME: from SYSTEMstat?.
amp_nameampName from the one-shot JSON probe (user-renamable).
global_temp, global_voltage, global_protection, thermal_protectionParsed from SYSTEMstat? lines.
active_zonesJSON list of the names of zones currently powered on, recomputed after each SYSTEMstat? poll settles (read-only at-a-glance summary of what the amp is driving).
last_errorLast poll error message.

Zone

  • Address required: yes.
  • Address format: numeric 1..N for wired zones, a / b for Digital Out zones.

The driver writes the following onto each polled zone:

AttributeTypeSource
power_statestringon / off
mute_statestringon / off. The regular status poll does not report mute, and there is no dedicated mute-query command, so this only populates if you issue a raw mute query through passthrough (e.g. Z1mute?).
volumeintCurrent zone volume (0–100 scale).
inputstringRaw source label the zone is currently on, exactly as the amp reports it — e.g. MX13 & 13 (matrix channel pair), DXa (Digital In A), Local. This is the source label, not a numeric id.
signal_sensestringon / off

Which zones receive state

Two bindings deliver poll state to a zone, and either one is enough:

  • Direct — the zone's own device is the amp and the zone address is the amp output (1..N, a/b). This is what auto-create sets up. The full row syncs: power_state, input, volume, signal_sense.
  • Via AV routing — the zone's AV Zone lists the amp as its volume device and carries the amp output in the AV Zone address (or in the ar= component of a compound address). This is the usual shape for a room whose zone belongs to its display device (a TV, a receiver) while the amp only handles audio. volume and mute_state always sync from the amp — the volume device owns them. power_state, input and signal_sense sync only when the zone has no device of its own; when another device owns the zone, that device owns those attributes.

You do not need to re-point a zone's device/address at the amp just to get volume updating — the AV Zone volume-device link is sufficient.

Commands

Power & status

CommandArgsNotes
power_on / power_offWhole-amp power.
query_statusIssues SYSTEMstat?; populates global telemetry attributes.
query_voltage / query_temp / query_protect / query_shortSingle-value queries.
query_groups / query_amp_name
query_zone_on / query_zone_off / query_input / query_group_input
sync_zonesForce a zone status poll now and auto-create any missing GEM zones.
sync_av_zonesWalk the main (numeric) zone outputs and ensure a matching AV Zone row exists. Digital Out zones are skipped.
all_zones_on / all_zones_off
mute_all / unmute_allMute or unmute every zone at once.

Zone control

CommandArgsNotes
zone_on / zone_offaddressPer-zone power.
volumeaddress, volumeSet absolute zone volume. The amp reports volume on a 0–100 scale.
volume_up / volume_downaddressStep the zone volume up/down by one increment.
mute_on / mute_offaddress
set_bass / set_trebleaddress, level
bass_up / bass_down / treble_up / treble_downaddress
loudness_on / loudness_offaddress
zone_signalsense_on / zone_signalsense_offaddressPer-zone signal sense.
all_signalsense_on / all_signalsense_offGlobal.
get_volumeaddress
recall_eqaddress, preset (1-6)
query_zone_stat / query_zone_eq / query_zone_bass / query_zone_treble / query_zone_loudness / query_zone_input / query_zone_signalsense / query_zone_poweraddress
get_zone_inputaddressAlias of query_zone_input.

Source routing

CommandArgsNotes
set_sourceaddress, source_idM-series numbered local source (legacy). For D2800 / D4600 fixed sources use set_input with local / bus_a / bus_b instead.
set_inputaddress, inputRoute any source to a zone. A bare 1-8 selects matrix channel pair MX1-MX8 (pairs 1-2 … 15-16). D2800 / D4600 fixed sources may be given as LX / BXa / BXb or as local / bus_a / bus_b, and full codes (MX3, DXa, V0CS2) pass through verbatim. Digital In runs DXa-DXd on the four-input models.
set_dante_inputaddress, input (raw suffix)Route a Dante source by raw source suffix — e.g. V0CS3 (Dante input 3 via Dante Controller), V1CS2 (AudioControl Dante amp source), MX5 (matrix), DXa (digital). Appended after Z[n]source.
set_source_danteaddress, dante_id, input_indexM6800D / Director: route a Dante source to a zone. dante_id 1-8 = AudioControl Dante amps (0 for non-AudioControl sources via Dante Controller); input_index 1-8 stereo pair from amp web UI. Digital inputs cannot be Dante-routed.
set_outputaddress (a/b), inputRoute any source to Digital Output A or B. A bare 1-8 selects matrix channel pair MX1-MX8; full codes (MX3, DXa-DXd, V0CS2) pass through verbatim. Replaces set_digital_output, set_dxo_source_matrix and set_dxo_source_dante — macros naming any of those still route correctly.
query_dxo_inputaddress (a/b)Query the source currently routed to Digital Output A or B. The arg was output before it was aligned with set_output; macros still passing output keep working.

Lipsync (D4600 zones 5-8)

CommandArgsNotes
lipsync_up / lipsync_downaddressStep delay by 5 ms.
set_lipsyncaddress, steps (0-19)5 ms per step.

Groups

CommandArgsNotes
group_zoneaddress, group_idAdd zone to a group.
ungroup_zoneaddress, group_idRemove a zone from a group.
group_volumegroup_id, volumeSet every zone in a group to a volume.
group_mute / group_unmute / group_on / group_offgroup_id

Escape hatch

CommandArgsNotes
passthroughinputSend a raw telnet command to the amp. The string is transmitted verbatim. Useful for one-off diagnostics or commands not yet wrapped by the driver.

Known quirks

  • The amp does not push state changes — front-panel volume / source changes only appear after the next poll.
  • Only the powered outputs auto-create zones, with numeric ids. Digital Outs are skipped — they typically feed a whole-house source to a zone with its own local receiver rather than driving a room. Add one manually with address a / b if a site controls it directly.
  • AV zones aren't auto-created on connect — run sync_av_zones once to populate them (main zone outputs only; Digital Out zones are excluded).
  • D-series input codes. The D2800 / D4600 have no numbered MX inputs. Each zone has three fixed sources: Local (LX) — the per-zone RCA pair above that zone's speaker outputs — plus the two shared analog buses, Bus A (BXa) and Bus B (BXb), each of which can feed any number of zones at once. The firmware also accepts the M-series codes as aliases: MX2 = Local, DXa = Bus A, DXb = Bus B. set_input expands whichever spelling you give it, so a generic AV source macro that passes the av source's address into set_input works on both families — put BXa (or bus_a) in the av source's address field and reference it from the macro's command step as [av_source_address]. M-series numbered local sources still use the legacy set_source.
  • Garbage commands echo back as xx<cmd>xx and are logged as warnings — useful for catching typos in custom macros.

Troubleshooting

SymptomCheck
Zone state diverges from front panelLower sync_interval or run sync_zones manually; the amp does not push events.
Zone physically on but GEM shows it off (e.g. an off command lost to a network blip)Self-heals: the driver's power_state poll feeds GEM's physical power reconciliation, which restores the zone's source (macros suppressed) so the off controls return. Opt out per zone with power_reconcile = false.
Model never populatedOne-shot JSON probe failed; check http://<ip>/json/signalprocessing.json in a browser, or watch logs for the telnet fallback.
sync_zones reports errorsConfirm the av subsystem exists in GEM — auto-created zones live under it. Also confirm telnet on port 23 is reachable.
A zone was created with the address appended to its name (..._3)Another zone already held the plain name. Expected — rename the zone's label freely; the name only has to stay unique.
Log says zone row exists but is not loaded, skipping createA zone row for that address exists but isn't in the live collections — usually its subsystem is disabled, or the row was disabled. Re-enable it and reload the device.