Skip to main content

AVPro Edge AC-MAX

The avpro_acmax driver controls the AVPro Edge AC-MAX audio matrix / distribution amplifier. It speaks the AVPro ASCII IP control protocol over TCP — plain text commands such as SET OUT1 VOL 45, \r\n terminated in both directions, no login. The AC-MAX routes any input to any output and gives each output its own volume, mute, and on/off, so in GEM it is a controller: one device drives many zone outputs and switches between many source inputs.

You bind each output to an AV zone and each input to an AV source. Once an AV zone's Volume Device points at the AC-MAX, the zone's volume/mute controls dispatch to that output and the matrix mirrors the output's state back onto the zone.

Prerequisites​

  • The AC-MAX on the same LAN as GEM, with a static IP or a DHCP reservation.
  • IP control enabled in the AC-MAX web UI. Note the control port shown there — you enter it when you create the device.
  • A list of which physical OUT number feeds each room and which IN number each source is wired to. AVPro numbers OUT/IN ports 1-based; confirm the numbering printed on the chassis matches the labels in your rack drawings before you start.
Addressing

Throughout GEM, an AC-MAX AV zone address is the output (OUT) number and an AV source address is the input (IN) number — both 1-based integers that match the chassis. The query OUT0 is a wildcard the driver uses internally to read all outputs at once; you never enter 0 as a real zone address.

Setup​

Matrix Setup tab

The device's Setup tab does steps 2-4 below from one screen: a live crosspoint grid (sized by Input Count / Output Count, read-only until you turn on Route on click), Create routing macro (one macro that sends input with the selected source and room), a Create source row per input, and an AV zone picker per output. It lists only AV zones whose volume device is this AC-MAX, and assigning one to an output sets both its address and its volume device, after asking if it pointed elsewhere. The grid reads each route from the room's zone, which is where this driver reports it, so there are no separate output zones to create. A newly assigned AV zone starts reporting right away; before, the driver only picked up AV zone changes when it reconnected. See Devices — Setup Tab.

  1. System → Devices → Add Device: choose driver AVPro Edge AC-MAX (avpro_acmax). Set ip to the matrix's LAN address and port to the IP control port from the AC-MAX web UI. Set Enabled to Yes and save. On connect the driver reads every output's volume, mute, routed input, and on/off state once (a wildcard OUT0 sweep), so the current matrix state populates immediately.

  2. AV → AV Zones → Add — create one AV zone per output you want to control:

    • AV Type — audio (use video only if you are mapping a video output).
    • Volume Device — the Device that controls volume for this zone picker. Set it to the AC-MAX. This is what makes the zone's volume and mute controls reach the matrix output.
    • Address — the OUT number for this room (e.g. 3 for OUT3). If you use the Advanced addressing toggle instead, put the output number in the Audio Routing field; the driver reads the audio routing address first, then the plain Address.
  3. AV → AV Sources → Add — create one AV source per input:

    • Device — the physical source feeding that input (cable box, streamer, media server).
    • AV Type, Label — required; the label is what users see when they pick the source.
    • Address — the IN number this source is wired to (e.g. 5 for IN5).
    • On Macro — the route command (see Routing a source to a zone below).
  4. On a touchpanel, selecting a source for the zone runs that source's On Macro to route the input to the zone's output; the zone's volume/mute controls drive the output directly.

Routing a source to a zone​

GEM does not auto-route a matrix — a source is routed by its On Macro. Build one Run Command macro and reuse it for every AC-MAX source:

  1. Automation → Macros → Add a macro, e.g. Route AC-MAX.
  2. Add a step that sends the AC-MAX input command (wire: SET OUT[address] AS IN[input]).
  3. Leave its argument pickers on the AV defaults — address resolves to the AV zone's output address and input resolves to the AV source's input address. GEM fills both in at run time from whichever zone and source are involved, so the single macro works for all of them.
  4. Set this macro as the On Macro on each AC-MAX AV source.

When a user picks that source in a zone, GEM substitutes the zone's OUT and the source's IN and sends SET OUT<out> AS IN<in>. The driver then reports the new routing back, and the zone's input attribute updates.

Volume vs. source — two separate paths

Volume and mute flow automatically through the zone's Volume Device binding — no macro needed. Source routing is the On Macro above. Note the driver tracks the routed hardware input in the zone's input attribute; it never writes the zone's source field, which GEM manages from your AV source selection.

Attributes​

Device — required​

AttributeTypeDescription
ipstringLAN IP of the AC-MAX.
portintIP control (TCP) port shown in the AC-MAX web UI.

Device — optional​

AttributeTypeDefaultDescription
command_throttleint (ms)200Minimum spacing between commands sent to the matrix. Raise it if rapidly issued commands are dropped.
response_terminatorstring\r\nLine terminator the matrix uses. Leave it unless a non-standard firmware ships with a bare \r — in that case responses buffer forever and the driver never updates.
web_portint80HTTP port of the AC-MAX web interface. Used only by play_chime_http / stop_chime_http, which talk to the web UI's JSON endpoint rather than the control port.
input_count, output_countint16Matrix size for the Setup tab's crosspoint grid. The driver does not use them; set them to your model.
page_switch_settleint (ms)400How long page_zones holds its cover after a route change, in and out. The matrix takes a few hundred ms to move a crosspoint and the outgoing source plays through it, so the whole transition is covered. Raise it if a room still hears a slice of its own source; lower it toward 0 if the start of a live page feels late.
page_coverlevel / mutelevelHow page_zones silences an output while it moves. level sets the output to VOL 0 and steps it back to the page level (or its own) after the switch — a level set is instant on this unit. mute uses MUTE/UNMUTE, which on the AC-MAX is a slide of about 1.9 s each way, so the route is heard and the page fades in; keep it only for a unit or firmware where VOL 0 is not silence. An output whose level was never reported, or a unit with volume_ramp_time set, takes the mute cover regardless.
page_mute_settleint (ms)0How long page_zones waits after a MUTE cover before it routes. 0 because command_throttle already spaces those lines by more than a gain change needs, and every wait here comes out of a short page. Not spent under the level cover, which has landed when it is acked.
volume_ramp_timeint (ms)0How long this unit takes to reach a level it has been given, if it slides rather than steps. When set, a page goes under a mute cover and holds it until the level has arrived instead of unmuting into the ramp — both on the way in and on the way back, where the ramp is toward the room's own level. The wait overlaps the switch settle rather than adding to it. The AC-MAX measured here steps instantly; leave it 0.
Status reads happen on connect, not on a timer

The AC-MAX reads all outputs once when GEM connects (and again after any reconnect); it does not poll on a cycle. After that, the displayed state stays current because the driver applies the matrix's own confirmations to every command it sends. A change made outside GEM — at the AC-MAX web UI or front panel — shows up the next time GEM reconnects to the matrix, not immediately. If you need a manual refresh, run get_global_status or the per-output get_volume / get_mute_state / get_input queries.

Reflected zone attributes​

The driver writes these onto the bound AV zone as the matrix confirms each command and during the connect sweep:

AttributeTypeNotes
volumeintOutput volume, 0-100.
mute_statestringOutput mute, on / off.
inputintThe IN number currently routed to this output.
power_statestringOutput enable state, on (EN) / off (DIS).

These names are cataloged, so they appear in the Attribute editor's name picker and can drive attribute triggers — for example, alert when an output is muted (mute_state = on) or when input changes.

Zone / AV zone​

  • Address required: yes — the output (OUT) number, 1-based. Set it in the AV zone's Address field, or in Audio Routing under Advanced addressing. A zone whose Volume Device is the AC-MAX is what the driver tracks per output.

AV source​

  • Address: the input (IN) number, 1-based, in the AV source Address field. The source's On Macro routes this input to the chosen zone output.

Commands​

get_* commands take an output (address) or input (input) argument and return current state; the rest are control commands. The address argument is an AV zone (output) address and input is an AV source (input) address — the pickers offer your real zones and sources.

Routing & output power​

CommandArgsWireNotes
inputaddress, inputSET OUT[address] AS IN[input]Route an input to an output. Used by AV source On Macros.
zone_onaddressSET OUT[address] ENEnable (power on) the output.
zone_offaddressSET OUT[address] DISDisable (power off) the output.
set_output_statestate (EN/DIS), addressSET OUT[address] [state]Same as zone_on/zone_off with an explicit state.

Volume & mute (per output)​

CommandArgsWireNotes
volumeaddress, volume (0-100)SET OUT[address] VOL [volume]Set output volume.
volume_upaddressSET OUT[address] VOL+Step volume up.
volume_downaddressSET OUT[address] VOL-Step volume down.
mute_onaddressSET OUT[address] MUTEMute the output.
mute_offaddressSET OUT[address] UNMUTEUnmute the output.

Output tuning​

CommandArgsWireNotes
set_output_balanceaddress, balanceSET OUT[address] BAL[balance]Set the left/right balance for the output (range per AVPro documentation).
set_output_channel_configaddress, mode (0-3)SET OUT[address] CH CONFIG [mode]Set the output channel configuration; mode values per AVPro documentation.
set_output_followaddress, mode (0-3), leaderSET OUT[address] FOLLOW [mode] OUT[leader]Make an output follow a leader output so they track together. leader must be a different output; an output told to follow itself is refused.

Input controls​

CommandArgsWireNotes
set_input_volumeinput, volumeSET IN[input] VOLUME [volume]Trim the input gain.
set_input_stateinput, state (EN/DIS)SET IN[input] [state]Enable / disable an input.

Chime / paging​

CommandArgsWireNotes
play_chimeconfig (1-5)PLAY CHIME [config] ENStart a built-in chime configuration.
stop_chimeconfig (1-5)PLAY CHIME [config] DISStop a chime configuration.
play_chime_in_zonesconfig, zones, duration, volume, file—Play a chime through specific zones with auto-restore (see below).
page_zonesinput, zones, duration, volume—Route one input into specific zones for a window, then restore them (see below).
stop_page——End the running page immediately and restore every paged zone.
play_chime_httpfile, repeat, durationHTTP POST /doPlay a chime over the web UI endpoint instead of the control port (see below).
stop_chime_http—HTTP POST /doSend stopaudio over the web UI endpoint. Resets the audio player.

play_chime_in_zones is the doorbell / paging helper. Call it from a macro Send Command step (or a trigger) against the AC-MAX device with these args:

  • zones — an array of AV zone ids to chime (a comma-separated list is also accepted).
  • config — chime configuration 1-5 (default 1).
  • file — chime file 1-5 (default 1).
  • duration — milliseconds the chime plays (default 5000; 0 or a negative value also uses 5000).
  • volume — chime volume 0-100 (default 40). A value that is not a number is refused with volume must be a number and nothing plays.

The driver enables any listed output that is currently off and unmutes any that is muted (a muted output would play no chime), plays the chime through all of them, waits duration, then restores exactly what it changed — re-muting the outputs that were muted and turning back off only the outputs it had to turn on. Outputs that were already playing are left running. This makes it safe as a doorbell or page that does not disturb whatever the rooms were doing.

The sequence is drop-resilient: the AC-MAX can silently kill an idle control session, which used to swallow chimes whose enable/play lines raced the reconnect. The driver now keeps the link warm with a keepalive query (GET OUT1 EN every 30 s when idle) and, if any line of the chime sequence still hits a dead socket, waits for the reconnect, redoes the whole prep phase (enables and unmutes — both idempotent), and plays — logging avpro acmax chime interrupted by socket drop when that happens. A chime that could not be delivered returns an error instead of pretending it played.

page_zones — route a live input into rooms​

play_chime_in_zones plays the matrix's own audio file. page_zones is its sibling for a live input: a door station, a paging microphone, an intercom or a paging amplifier wired to one of the AC-MAX inputs. It routes that input into the zones you name, holds them there, and then puts every zone back on the source, volume, mute and power state it was sitting on.

Call it from a macro Send Command step or an attribute trigger (a door-station button press, a gate contact, a mic PTT contact) against the AC-MAX device:

  • input — the IN number the door station / microphone is wired to. Required.
  • zones — the AV zone ids to page: an array, a JSON array, a comma-separated list, or a single id.
  • duration — milliseconds to hold the page (default 10000). 0 holds the page open until stop_page — the live-microphone case, where nobody knows in advance how long the talker talks.
  • volume — page volume 0-100. Optional: leave it out and each room pages at whatever level it was already set to, which is usually what a microphone page wants; a door station normally names one.

What the driver changes, it changes back. Per zone it enables an output that was off, routes the input, then brings the level up to the page volume — and on the way out restores the source first, then the power, then the mute state the zone was found in, then the level, so a room that stays on is back on its own audio before anything of it becomes audible again. A room that was already playing its own music at its own level is returned to exactly that. A room that was muted before the page is opened up for the page and muted again after it — a muted output plays no page.

Every transition is covered. The AC-MAX does not move a crosspoint instantly: the outgoing source keeps playing for a few hundred milliseconds after the route line is acknowledged. A bare route would therefore hand each room a slice of whatever it was playing — at the page volume, if the page named one, which is the loudest possible way to hear it — and a slice of the door station on the way back. So the driver silences every output it is about to move, routes underneath the cover, waits page_switch_settle (400ms by default) for the switch to finish, and only then uncovers — all the rooms together, so the page starts everywhere at the same moment rather than walking around the house one output at a time. The restore runs under the same cover. The duration you ask for is audible page time: the transition is not counted against it.

The cover is a level, not a mute. On the AC-MAX, MUTE is not a gain cut. The unit acknowledges it at once and then slides the output to silence one step at a time — 1876 ms end to end on the unit this was measured on, 77 steps at about 25 ms, each reported as its own OUT13 VOL n line — and UNMUTE slides back up the same way. A route sent one throttle gap after a MUTE therefore moves the crosspoint while the room is still near full level, so the listener hears the switch the mute was meant to hide, and the page then fades in over another 1.9 s, so a three-second door chime is half over before the room is at level. SET VOL steps instantly (one report line, no slide). So the driver covers with SET OUT n VOL 0 and uncovers with SET OUT n VOL at the page level, or the room's own: both land the moment they are acknowledged, nothing is waited for between the cover and the route, and the page starts at full level. The room's own level goes back the same way on the restore — after the room is on its own source, off if it was off, and muted if it was muted, so the stored level is right for the next time someone unmutes it. Two rooms take the old MUTE/UNMUTE cover instead, and say so in the log: one whose level the matrix has never reported (there is nothing to put back — the same rule as an unreported source), and one on a unit that ramps (volume_ramp_time set), where the uncover would itself be a fade-in. page_cover: mute switches the whole driver back to the mute cover for a unit or firmware where VOL 0 turns out not to be silence.

A room that was already muted before the page is the one case that still slides: opening it is a real UNMUTE, and there is no instant way to unmute this unit. It is routed under its own mute, given the page level there, and unmuted with the rest of the rooms; on the way back it is covered at VOL 0, re-muted at 0 (nothing to slide from) and then handed its stored level back.

Still hearing a slice, or waiting too long for the page?

Check page_cover first: with mute, both symptoms are expected. Then raise page_switch_settle if a room still catches a moment of its own source; lower it if the start of a live page feels late. 0 disables the wait entirely (the cover and uncover lines are still sent). page_mute_settle only applies to a MUTE cover and is 0 by default — the command throttle already spaces those lines.

Timing budget — a three-second door chime​

A door station's chime is live audio: it starts when the button is pressed, whether or not the rooms are listening yet. Everything between the press and the uncover comes out of it, and on this matrix that is mostly queue time, not settle time: every line is spaced by command_throttle (200ms by default) and the cover costs two extra lines per zone. A one-zone page spends roughly 3 lines × throttle + settle (four with a room that was off); an eight-zone page spends eight times the lines. If a short chime is half over before the rooms hear it:

  • Lower command_throttle on this device — the single biggest lever, and it speeds up everything else the matrix does too. The matrix itself pipelines: twenty commands fired back-to-back were all answered within a 15 ms window, and a sweep from 200 ms down to 0 ms dropped nothing, so 25 ms is defensible. Lowering it makes GEM write faster; the ack still comes 100–300 ms later, on the unit's own reporting cycle.
  • Page fewer zones per call, or give the paged group its own smaller zone list.
  • Lower page_switch_settle to the shortest value that still hides the switch. The route ack carries the new crosspoint at about 300 ms.
ZonesLinesQueue at 200 msQueue at 25 ms
13~1000 ms~475 ms
412~2800 ms~700 ms
1030~6400 ms~1150 ms

Queue time is lines × throttle plus the 400 ms settle; rooms that were off add a line each.

The duration you ask for is not part of this: it is measured from the moment the page becomes audible, so a 3000ms page is 3000ms of audible page no matter how long the transition took.

If a page starts at the wrong level and slides up to the right one in a room that was not muted beforehand, the unit ramps to new levels rather than stepping to them — time the slide and set volume_ramp_time to it. The page then goes under a mute cover and holds it until the level has arrived, and because that wait overlaps the switch settle it only costs whatever is longer than the settle. (A room that was muted slides on every page: that is the unit's UNMUTE.)

A page always ends

A page started with duration: 0 still self-ends after 5 minutes even if stop_page never arrives, and a device reload or disable ends it immediately. A mic page whose stop is lost must not leave the house listening to the front door.

Retriggering is safe. Pressing the button again — or a second door station paging while the first window is still open — folds any new zones into the page already running, extends the window, and still performs a single restore at the end. Each zone's pre-page state is captured the first time that zone joins, so a re-route never records the door station as a room's own source. A room that is already carrying the page is left strictly alone: re-routing it to the input it is already on would mean muting audio someone is listening to, so only the newly added rooms make the trip.

Restoring the source relies on the matrix having reported what each output was routed to. The connect sweep reads every output, so this is known after any connect. For an output that has never reported its routing the driver leaves the page input in place and logs page cannot restore source, prior input unknown rather than guessing a source the user never selected — run get_input for that output, or reconnect the device, and the next page restores normally.

Like the chime, the sequence is drop-resilient: any line refused by a dead control session makes the driver wait for the reconnect and redo the whole prep-and-route pass (every line is idempotent), and each restore line gets one retry of its own. A page that could not be delivered returns an error instead of pretending it played.

play_chime_http — the web UI fallback​

On some firmware the ASCII PLAY CHIME command stops producing audio while the matrix still accepts and acknowledges the line — nothing errors, the chime simply never plays. The AC-MAX's own web UI does not use that command. When you press play on the ioconfig page it posts to a JSON endpoint on the web port, twice, and then always posts a stopaudio:

POST http://<matrix-ip>/do {"cmd":"c s playaudio 1001"}
POST http://<matrix-ip>/do {"cmd":"c s playaudio 1001"}
POST http://<matrix-ip>/do {"cmd":"c s stopaudio"}

play_chime_http reproduces that sequence. The repeat appears to be the vendor's own workaround for the first post being dropped, and the trailing stopaudio resets the audio player — leaving it un-reset is what wedges the endpoint for the next chime.

  • file — audio file id as numbered in the web UI's audio list (default 1001). Note this is a different numbering space from play_chime_in_zones's file arg.
  • repeat — how many play posts to send (default 2, clamped to 1-5).
  • duration — milliseconds to let the chime run before the stopaudio (default 5000). 0 sends the reset immediately after the plays.

The reset is sent whether or not you asked for a wait, because skipping it is what leaves the endpoint stuck. If chimes have already stopped firing, run stop_chime_http once by hand to unwedge the player.

The endpoint answers 200 {} for every command, including a file that does not exist — it reports transport success, not playback success. A failed post (refused, timed out, 4xx) returns an error and the sequence stops there.

This path talks to the web port, not the ASCII control port. It defaults to 80; set a web_port device attribute if the web UI is on another port.

Queries​

CommandArgsWire
get_volumeaddressGET OUT[address] VOL
get_mute_stateaddressGET OUT[address] MUTE
get_inputaddressGET OUT[address] AS
get_output_stateaddressGET OUT[address] EN
get_output_followaddressGET OUT[address] FOLLOW
get_input_stateinputGET IN[input] EN
get_input_volumeinputGET IN[input] VOLUME
get_input_signal_statusinputGET IN[input] SIG STA
get_global_status—STA
get_system_status—GET STA
get_config—GET CONFIG
get_dhcp_state—GET DHCP
get_mac_address—GET MAC

System​

CommandArgsWireNotes
reboot—SET RBTReboot the matrix.
help—HDevice help / command list.
passthroughcommand[command]Send a raw protocol command verbatim — the escape hatch for anything not modeled above.

Known quirks​

  • OUT/IN numbers are 1-based and must match the chassis labels. OUT0 is an internal all-outputs query, never a real zone address.
  • Status is read on connect, not on a poll. Changes made directly at the AC-MAX (web UI or front panel) appear after GEM's next reconnect. Run a get_* query for an on-demand refresh.
  • Terminator sensitivity. The driver expects \r\n. Firmware that replies with a bare \r makes the driver buffer responses indefinitely — set the response_terminator attribute to match in that rare case.
  • An output can follow another. If a room never changes volume independently, check get_output_follow — set_output_follow may have it tracking a leader output.
  • A page restores from reported state. page_zones puts each zone back on the source, volume, mute and power the matrix last reported for that output. The connect sweep reads all of them, so this is known after any connect; an output that has never reported its routing keeps the page input and the driver logs it.
  • A crosspoint change is not instant. The outgoing source plays for a few hundred ms after the matrix acknowledges a route line. page_zones covers each output for the whole transition (SET VOL 0, the level put back page_switch_settle after the route), in and out, so a paged room never hears a slice of what it was playing. Ordinary source selection (the input command, a source On Macro) is unaffected — only paging takes the cover.
  • MUTE is a slide, not a cut. The unit acknowledges MUTE at once and then steps the output down to 0 over about 1.9 s, reporting a VOL line per step; UNMUTE slides back up the same way. SET VOL steps instantly. That is why paging covers with a level rather than a mute, and why a burst of VOL report lines after a mute is normal, not protocol noise.
  • PLAY CHIME can go silent while still being accepted. On some firmware the ASCII chime command is acknowledged but plays nothing. Use play_chime_http, which posts the same play-twice-then-stopaudio sequence the AC-MAX web UI uses.

Troubleshooting​

SymptomCheck
Volume or mute does nothing for a zoneConfirm the AV zone's Volume Device is set to the AC-MAX and the zone Address is the correct OUT number.
Source select does not switch the inputThe source needs an On Macro that runs the input command (see Routing a source to a zone), with its input argument set to the source's IN number ([av_source_address]). Older macro steps built before input appeared in the step's parameters may not set it — open the step and fill it in. Confirm the source Address is the right IN number.
Output appears stuck offThe output may be disabled (get_output_state returns DIS) or following another output (get_output_follow). Send zone_on, or clear the follow with set_output_follow.
State never updates after a route changeConfirm response_terminator is \r\n; some firmware ships with a bare \r and the driver will buffer responses indefinitely.
Reported state is stale after a web-UI changeStatus is read on connect, not polled. Reconnect the device, or run get_global_status / the per-output queries.
Chimes stopped playing but the matrix answers everything elseThe audio player is wedged. Run stop_chime_http once to reset it, then move the chime source to play_chime_http.
A page leaves rooms on the door station instead of their own sourceThat output had never reported its routing, so there was nothing to restore (look for cannot restore source, prior input unknown). Run get_input for the output, or reconnect the device so the connect sweep reads every output.
A page never endsIt was started with duration: 0, which holds until stop_page. Send stop_page to hand the rooms back now; otherwise it self-ends after 5 minutes.
A room hears a moment of its own source (or of the page) during a page transitionWith page_cover set to mute this is expected — the route lands while the mute is still sliding down. Leave page_cover at level. If it persists, raise page_switch_settle on the device — it is how long the output stays covered after the route line, and this matrix needs a few hundred ms to finish a switch. The opposite symptom, a page that starts late, means it is set too high.
A room is silent after a page (volume at 0, or its mute on)The page's cover is lifted by the restore. Look for page restore error in the log, or a device reload during the page window; setting the zone's volume, or mute_off on the zone, clears it.
A short page is half over before the rooms hear itFirst check page_cover is not mute: MUTE/UNMUTE are ~1.9 s slides on this unit, so a mute-covered page fades in over its first two seconds. Then queue time: every line is spaced by command_throttle (200ms) and the cover adds two lines per zone. Lower command_throttle (the unit pipelines cleanly; 25ms was measured drop-free), page fewer zones per call, and lower page_switch_settle. See Timing budget.
A page starts quiet and slides up to the right volumeEither the room was muted before the page — opening a muted room is an UNMUTE, which this unit slides — or the unit ramps to new levels. For the second, time the slide and set volume_ramp_time to it; the page then goes under a mute cover and holds it until the level has arrived.
  • AV Zones — bind each output as a zone's Volume Device.
  • AV Sources — define the inputs and their routing macros.
  • Macros — build the source On Macro and the paging chime.
  • Devices — add and configure the matrix.
  • Commands — the command grid and the Test runner.