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​

Matrix Setup tab

The device's Setup tab shows the amp as a grid of matrix channel pairs MX1-MX8 by wired zones (sized from Zone Count) with what each zone is on now, and wires AV routing: Create routing macro makes one macro that runs set_input with the selected source and room, and Create source makes an AV source per channel pair with that macro as its On Macro. Digital Outs, Dante and local/bus sources stay outside the grid. A zone whose input reads anything other than an exact MX<n> shows no route in the grid rather than a guess. The Outputs list shows an AV zone against an output only when this amp is its volume device (what sync_av_zones writes), so another amp's zone 1 never appears here; assigning an AV zone to an output makes this amp its volume device, after asking if it had another. See Devices — Setup Tab.

  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_off—Whole-amp power.
query_status—Issues SYSTEMstat?; populates global telemetry attributes.
query_voltage / query_temp / query_protect / query_short—Single-value queries.
query_groups / query_amp_name—
query_zone_on / query_zone_off / query_input / query_group_input—
sync_zones—Force a zone status poll now and auto-create any missing GEM zones.
sync_av_zones—Walk 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_all—Mute 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 must be a number.
volume_up / volume_downaddressStep the zone volume up/down by one increment.
mute_on / mute_offaddress
set_bass / set_trebleaddress, levellevel must be a number; it is not range-checked.
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_off—Global.
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_poweraddressquery_zone_input and query_zone_power update the zone's input / power_state. The replies to the stat, eq, bass, treble, loudness and signal sense queries are logged but not yet written to zone attributes — their reply format has not been confirmed against a unit.
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. Out-of-range values are clamped to those ranges. 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. A value outside 0-19 is clamped to the nearest end.

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.
  • Numeric arguments (volume, level, steps, dante_id, input_index, group_id) are checked before sending. A value that is not a number is refused with an error such as volume must be a number, and nothing is sent to the amp. A valid value is sent exactly as given (05 stays 05).

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.