RTI AD-4x / AD-8x (HTTP)
GEM driver rti_ad8x_http controls an RTI AD-4x / AD-8x multi-zone audio distribution amplifier over the local HTTP control interface (rti_*.cgi) served at port 80.
Functionally equivalent to the rti_ad8 TCP driver — pick this one where the TCP control port becomes unresponsive after extended uptime. The web UI keeps responding on units where the TCP socket has wedged.
What it does
- Per-zone power, mute, volume, and source select via GET requests to
rti_zp0/zp1.cgi,rti_zm0/zm1.cgi,rti_zvs.cgi,rti_zi.cgi. - Periodic poll of
rti_status.cgito reconcile state — the amp does not push updates. - Optimistic state push on each command so the UI updates without waiting for the next poll.
- Transparent re-login when the amp serves the login page in place of a CGI response (silent session expiry).
- Publishes an
active_zonesdevice attribute — the list of currently powered-on zone names — refreshed on each status poll, only changing when the on/off set changes. Surface it on a dashboard widget or in the device's attribute view to see what's playing at a glance.
Prerequisites
- AD-4x or AD-8x amplifier on the LAN with HTTP control enabled (port 80 by default).
- Web-UI password — the one set on the amp's
rti.shtmllogin page. Leave the GEM attribute blank to use the factory default (rti).
Setup steps
- Confirm
http://<amp-ip>/rti.shtmlloads the RTI login page. - Create the device with driver
rti_ad8x_http, enter the IP, and set the web-UI password. - Add a GEM Zone for each amplifier output. Set
zone.addressto1..4(AD-4x) or1..8(AD-8x) — this is the value the amp expects in thez=query parameter. - On connect, the driver logs in, polls
rti_status.cgi, and refreshes everystatus_intervalms (default 5000). If the amp is unreachable or refuses the password at connect, the driver keeps trying to log in — after 30 seconds, then doubling up to every 5 minutes — and starts polling as soon as a login succeeds. No reload is needed once the amp comes back.
Attribute reference
Device
| Name | Required | Description |
|---|---|---|
ip | yes | LAN IP of the amplifier. |
password | no | Web-UI password. Sent to /rti_login.cgi?pw=… on each session. Defaults to rti. Stored as a secure attribute. |
port | no | HTTP port. Defaults to 80. A blank, 0 or non-numeric value uses 80 (a non-numeric one also logs a warning). |
status_interval | no | Poll interval (ms) for rti_status.cgi. Defaults to 5000. A blank, zero, negative or unreadable value uses 5000; values below 500 are raised to 500. |
request_timeout | no | Per-request timeout (ms). Defaults to 10000. A blank, zero or unreadable value uses 10000. |
volume_min | no | Soft floor on GEM volume (0..100). Requests below this are clamped before being sent. Defaults to 0 (no floor). |
volume_max | no | Soft ceiling on GEM volume (0..100). Useful for capping how loud a zone can be driven. Defaults to 100 (no cap). |
debug_log_status | no | When true, dumps the first status response body per connect to the log for parser tuning. |
Zone
No required zone attributes. Set zone.address to the 1-based output number.
Reflected attributes (read-only)
The driver writes these from each status poll — and optimistically on each command — so they stay in sync with the amp. You do not set them by hand; they appear on the zone (or device) once polling is running.
| Target | Name | Type | Notes |
|---|---|---|---|
| Zone | power_state | string | on / off. |
| Zone | mute_state | string | on / off. |
| Zone | volume | int | 0..100 (GEM scale). |
| Zone | input | int | The physical amplifier input currently routed to the zone (see set_input). The driver writes input, never source — see the note under Known limitations. |
| Device | active_zones | json | Array of the names of every powered-on zone, recomputed on each poll. Handy as the data source for a dashboard widget. |
Commands
| Name | Args | Notes |
|---|---|---|
zone_on / zone_off | address | Powers the zone on or off. |
mute_on / mute_off | address | Mute control. |
volume | address, volume | Volume 0-100 in GEM units; converted to wire dB internally. |
volume_up / volume_down | address | ±5 GEM units from the cached current value. |
set_input | address, input | Route a physical amp input (1-based) to a zone. Writes the value to zone.input. Implicitly powers the zone on. |
all_zones_on / all_zones_off | — | Power every GEM zone configured on this device (sequential fan-out, one HTTP request per zone). |
mute_all / unmute_all | — | Mute / unmute every configured zone (sequential fan-out). |
request_status | — | Trigger an immediate status poll. |
passthrough | path | Send a raw GET to the amp. path is the URI after the host, e.g. rti_zp1.cgi?z=1. |
A command reports {error: ...} when the amp could not be reached, answered with an HTTP error status, rejected the parameters (parameter error), or answered with its login page because the session could not be re-established (reauth failed / not authenticated). No optimistic state is written in any of those cases. The fan-out commands report success: false with error: 'all zones failed' when every zone failed, and include a failed count when only some did.
Volume scale
GEM exposes 0..100; the wire is dB attenuation -78..0 (0 = loudest, -78 = quietest). The driver converts in both directions. The rti_status.cgi body reports volume as an unsigned attenuation (e.g. "vol":"56" = -56 dB); the driver inverts the sign before mapping to GEM units.
Use volume_min / volume_max to cap or floor the GEM-side range — these are soft caps on the write path only, so a value set above the cap from the front panel still surfaces accurately on the next status poll.
Known limitations
- The amp does not push state — all reads happen via the polling interval. Lower
status_intervalfor tighter UI sync at the cost of more LAN traffic. rti_status.cgireturns near-JSON with SSI comments inlined ({"zone": <!--#zn1-->{...}}). The driver strips comments before parsing and infers zone numbers from the array index, since the JSON itself does not carry them.- Sessions are held by client IP — no cookie is set by most firmware. The driver re-logs in transparently when the amp serves the login page back in place of a CGI response.
- Success and failure both return HTTP 200. The driver disambiguates on body content (
<!-- ok -->for success, an HTMLParameter Errorpage for failure). - The amp's web server occasionally resets a single connection (roughly one poll in 10,000). The driver only marks the device offline after 3 failed polls in a row (~15 s at the default interval), so an isolated reset no longer flips it offline for a poll. A site that set
connection_failure_thresholdto something other than1keeps its own value. - While the amp stays unreachable, polling backs off: after the third failed poll in a row the interval doubles each time, up to once a minute (or
status_interval, if that is longer). The outage is logged once and the recovery once. The first successful poll restores the normal interval. Commands are never held back — they are sent immediately. - A wrong password marks the device disconnected. The amp answers a refused login with HTTP 200, which used to show the device as connected even though nothing worked.
set_inputimplicitly powers the target zone on — observed on AD-8x firmware. Setting a source on a powered-off zone will showpwr=1on the next status poll.
The driver writes the amp's physical input number (1..N) to zone.input. It never writes zone.source — that attribute is reserved for GEM's av_source foreign key and is owned by the AV-routing macros. Writing the raw amp input into zone.source would be rejected by the av-source-change handler as an invalid av source.
Troubleshooting
| Symptom | Check |
|---|---|
| Login fails / status returns HTML / device shows disconnected. | Confirm the password attribute matches the rti.shtml web UI password exactly. With a wrong password the device shows disconnected, and the driver retries the login every 30 seconds, backing off to every 5 minutes. |
| Volume slider feels backwards or compressed. | The driver maps GEM 0..100 onto the amp's -78..0 dB attenuation range (0 = loudest, -78 = quietest accepted). Some legacy firmware used a narrower range (around -62..0); on those units GEM volume reads proportionally lower than the front panel. |
| Zone state diverges from the web UI. | Lower status_interval; the amp does not push state, GEM only sees changes after the next poll. |
Commands rejected with parameter error. | Confirm zone.address is the 1-based output number (1-4 on AD-4x, 1-8 on AD-8x), not a padded string. |
If the existing rti_ad8 TCP driver works reliably for you, stick with it — TCP is lower-overhead. Switch to rti_ad8x_http if you see the amp's TCP control port stop responding after weeks of uptime while the web UI continues to work.