LEA Professional Connect Series
The lea_connect driver controls LEA Professional Connect Series amplifiers — both the
Network Connect models (analog inputs) and the Dante Connect models (analog plus Dante) —
over the published LEA Open API TCP protocol on port 4321. It covers the whole range, from the
2-channel 352 to the 8-channel 168N.
One amplifier channel is one GEM zone, addressed by channel number. The driver subscribes to each channel's state, so level, mute, channel enable, faults and load-monitor status arrive as the amplifier changes them — including changes made at the WebUI or by a fault — with no polling.
The TCP API needs LEA Connect firmware 1.1.0.x or later. Earlier firmware speaks only the
websocket API and will not answer on port 4321. The relative bump verb (fader_bump) needs
4.0.4.0 or later; nothing else in this driver depends on it.
How the protocol works
Everything in the amplifier is an element with a URL, and there are four verbs:
| Line sent | Amplifier answers |
|---|---|
get /amp/channels/1/output/fader | /amp/channels/1/output/fader -20.0 |
set /amp/channels/1/output/mute true | OK |
bump /amp/channels/1/output/fader -3 | OK |
subscribe /amp/channels/1/output/mute | the value now, and again on every change |
unsubscribe /amp/channels/1/output/mute | OK |
Every line in both directions ends in \n. Values containing spaces are double-quoted
("Analog 1+2"). Out-of-range numbers are clamped, not refused — an amplifier that answers OK
did not necessarily do what was asked, so the driver clamps before sending. Anything the amplifier
cannot parse comes back as error: ... with the offending line echoed, which the driver logs.
Subscribed state versus polled telemetry
The driver draws a hard line between the two, and it matters for attribute history:
- Subscribed — mute, output fader, channel enable, channel name, fault, thermal fault, ready, primary input source, and load-monitor status, per channel; plus the four power-supply status flags, auto-standby enable and the device name. These change when a person or a fault changes them.
- Subscribed, but gated by a hold — signal detect. The amp pushes it with the programme
material, so the attribute is written through
signal_hold_ms(see below). - Read once on connect — Hi-Z/Lo-Z mode, load-monitor enable, and the clip and limiting
indicators. Subscribe to the last two with
subscribe_protectionwhen you want to watch them. - Polled — AC line voltage, current and watts, on
power_poll_interval(default 60 s). - Polled only on request — per-channel output watts, volts and measured impedance, on
meter_poll_interval(default 0, off).
The driver never subscribes to a meter. The protocol guide's own example session shows a level
subscription pushing roughly ten updates a second, per channel; on an 8-channel amp that is a
firehose into attribute_history. Read meters on demand with get_meters, or accept the history
cost deliberately by setting meter_poll_interval.
Signal detect is the same kind of value, and on real hardware it is the loudest thing on the
connection. Measured on a 168N passing audio, signalDetect pushed about nine times a second
across eight channels over a 20-second sample, while every other subscribed element sat at its
connect value for the whole window. It stays subscribed — a channel starting to pass audio is worth
knowing at once — but the attribute is gated: presence is written as it arrives, and absence waits
out signal_hold_ms (3 s by default) and is cancelled by the next detection. That turns a
transient-rate element into the state-rate one a zone tile can render, and takes the steady-state
attribute write rate for an idle-but-playing amplifier to zero. Set signal_hold_ms to 0 to
record every transition.
Clip and limiting sit outside the subscribed set for the same reason. A limiter engaging on musical peaks is normal and can toggle several times a second on a hard-driven channel; across eight channels that is a stream of writes for something nobody acts on per event. Channel fault and thermal fault — rare, and worth acting on — are always subscribed.
Every value is change-guarded — an unchanged reading is not written.
Prerequisites
- Amplifier on the LAN over wired Ethernet or joined to an existing wireless network — not its own access-point mode — with a static address or a DHCP reservation.
- Firmware 1.1.0.x or later.
Setup
- In the amplifier WebUI, confirm the firmware version and network address, and name each output
channel. The driver reads those names; with
auto_create_zoneson it uses them to label the zones it creates. - System → Devices → Add Device: choose LEA Professional Connect Series
(
lea_connect), setip, leaveportat 4321, save and enable. - On connect the driver reads the device info, learns the channel count from
/amp/deviceInfo/numOutputs, and subscribes each channel. An 8-channel amplifier opens with about 120 lines at the default 50 ms throttle — roughly six seconds to fully converge. - Create one zone per amplifier channel, with
addressset to the bare channel number (1through8). Or setauto_create_zoneson the device and let the driver create them from the amplifier's own channel names. Existing zones are never touched, a channel whose zone you disabled is not recreated, and a channel name the amplifier repeats across outputs (the factory default isOutputNameon every channel) falls back to<device> Channel <n>so the zones stay distinguishable. - For a room that needs on-screen volume, set the AV zone's Volume Device to this amplifier and its audio output routing address to the channel number. Volume, mute and power state mirror back onto that zone.
Ganging the amplifier — group_all_zones
The amplifier has no grouping of its own (see the known quirks), so ganging is done here. With
group_all_zones on, the amp behaves as one logical output:
- Level, mute and channel enable sent to any zone are applied to every channel —
volume,volume_up,volume_down,set_fader,fader_bump,mute_on,mute_off,mute_toggle,on,off,power_on,power_off. - The resulting state is published to every zone, so all the tiles move together rather than seven of them showing a level nobody set.
The stateful verbs are resolved once, against the channel the caller addressed, and the absolute
result is sent to every channel. That matters: eight mute_toggles each computed from their own
channel would split the amp in half the first time one channel was muted on its own, and eight
volume_ups computed from eight different levels would stay eight different levels forever.
Per-channel tuning is not ganged. Crossover, EQ, limiters, load-monitor limits, input routing, Hi-Z mode and channel names stay on the channel they were addressed to. That is how a room is tuned — an installer trimming EQ on the channel feeding the back wall does not mean it for the other seven, and a gang that stamped one channel's tuning across the amp would be a commissioning accident rather than a feature.
Observations are aggregated rather than last-wins, because they genuinely differ per channel:
fault, thermal_fault, limiting, clip and signal_detect are reported for the group if any
channel reports them, and clear only when the last channel holding them lets go. Publishing
whichever channel reported most recently would make the group flap at the rate the channels
disagree. Everything else — impedance, load status, input source — stays a per-channel write to the
zone at that address, and the per-channel truth for the ganged values is always on the device as
ch<n>_<name>.
The protocol has no multi-channel addressing, so a ganged command is n separate writes at
command_throttle spacing — about 400 ms for an 8-channel amp at the default 50 ms. The channels
step rather than move in perfect lockstep.
Attributes
Device — required
| Attribute | Type | Description |
|---|---|---|
ip | string | LAN IP or hostname of the amplifier. |
Device — optional
| Attribute | Type | Default | Description |
|---|---|---|---|
port | int | 4321 | LEA Open API port. Fixed at 4321 on current firmware. |
channels | int | — | Channel count override. Normally read from the amplifier; set it only if the amp does not report one. |
fader_min_db | float | -80 | The dB value that volume 0 maps to. Raise it (e.g. -40) to spread a 0-100 slider over a more useful part of the fader. Clamped to -80..-1. |
volume_step | int | 2 | How far volume_up / volume_down move, in points on the 0-100 scale. |
power_poll_interval | int (ms) | 60000 | AC line voltage / current / watts read cadence. One sample is taken on connect, then on this interval. 0 disables it. |
meter_poll_interval | int (ms) | 0 | Per-channel watts / volts / impedance read cadence. When set, one sample is taken as soon as the channel count is known, then on this interval. 0 (default) disables it. |
subscribe_protection | bool | false | Subscribe to the per-channel clip and limiting indicators rather than reading them once on connect. |
signal_hold_ms | int (ms) | 3000 | How long signal presence must stay absent before the channel reports no signal. 0 writes every transition. |
auto_create_zones | bool | false | Create one zone per channel on connect, labelled from the amp's channel names. |
group_all_zones | bool | false | Gang the amplifier into one output — see below. |
command_throttle | int (ms) | 50 | Minimum spacing between lines sent to the amplifier. |
Reflected device attributes
| Attribute | Type | Notes |
|---|---|---|
model, serial_number, firmware_version, power_supply_firmware, hardware_id | string | From /amp/deviceInfo/. |
device_name, venue_name, rack_name, rack_position, asset_tag, installer_name | string | The amplifier's own naming fields. device_name is subscribed. |
date_of_manufacture, date_of_installation, uptime | string | As the amplifier reports them. |
channel_count, input_count | int | From numOutputs / numInputs. channel_count drives the subscription pass. |
ac_line_voltage, ac_line_current, ac_line_watts | float | Polled on power_poll_interval. |
power_supply_fault, power_supply_thermal, power_ok | bool | Subscribed power-supply status. |
line_voltage_ok | bool | true when the AC line is healthy. Inverted from the amp's lineWarning element — see the quirk below. |
fault_state, thermal_state | string | on / off rollups across the power supply and every channel — one trigger covers the whole amplifier. |
auto_standby, auto_standby_threshold, auto_standby_wait | bool / float / int | Auto-standby configuration. |
signal_generator_type, signal_generator_frequency | string / int | Amplifier-wide signal generator. |
ch<n>_volume, ch<n>_mute_state, ch<n>_power_state, ch<n>_fault, ch<n>_load_status, ch<n>_name | mixed | A compact per-channel summary, so an amplifier with no zones mapped yet still shows its state and can drive a trigger. Full channel state lives on the zone. |
Zone
Address required: yes — the bare amplifier channel number, 1 through 8. The driver refuses
anything else (ch1, 1:1) and logs the address it was given rather than framing a broken line.
| Attribute | Type | Notes |
|---|---|---|
volume | int | 0-100, mapped from the output fader. |
fader_db | float | The raw output fader, -80.0 to 0.0. |
mute_state | string | on / off. |
power_state, state | string | on / off, from the channel-enable element. Both are written — the zone tiles read state, the AV layer reads power_state. |
channel_name | string | The channel name stored in the amplifier. |
fault, thermal_fault, ready | bool | Subscribed channel status. |
signal_detect | bool | Subscribed, with absence held for signal_hold_ms. |
limiting, clip | bool | Read on connect; live only with subscribe_protection. |
load_status | string | Ok, Short, Open or Low Signal. |
load_monitor, load_high_limit, load_low_limit, impedance | bool / float | Load monitoring. impedance needs meter_poll_interval or a get_meters. |
input_source, secondary_input_source, input_priority_mode | string | Input selection. |
input_fader_db, input_level_db, input_signal_detect, input_clip | float / bool | Input stage. |
output_mode, hiz_hpf_frequency | string / int | LoZ / HiZ-70V / HiZ-100V and the Hi-Z high-pass. |
output_watts, output_volts, output_db | float | Meters — only written when polled or read on demand. |
rms_limiter, peak_limiter, rms_gain_reduction, peak_gain_reduction | bool / float | Limiter state. |
pilot_tone, pilot_tone_status, pilot_tone_level | bool / string / float | Pilot tone supervision. |
Commands
A command missing a value it needs is refused with {error: 'invalid <arg>'} and nothing is sent:
a numeric setting with no value or no number in it, a blank enum, boolean, element URL or
passthrough line, and a set_channel_name / set_device_name / set_venue_name with no name
at all (a blank name is still sent). Every value that was sent before is sent unchanged. While the
amplifier is unreachable a level or mute command answers socket not ready without moving the
zone tile, and get_status answers the same error instead of success.
Channel power, level and mute
| Command | Args | Notes |
|---|---|---|
on / off | address | Enable / disable the channel output. The zone on and off verbs. |
power_on / power_off | address | The same element as on / off. |
mute_on / mute_off | address | Mute / unmute the channel. |
mute_toggle | address | Resolved from the subscribed mute state — the protocol has no toggle. The new state is recorded as it is sent, so a second tap before the amplifier answers toggles back. |
volume | address, volume (0-100) | Mapped linearly in dB onto fader_min_db..0. |
volume_up / volume_down | address, step | Moves by step points (default volume_step). Computed from the subscribed fader and written absolutely, so it works on every firmware. |
set_fader | address, fader (dB) | Set the output fader directly, -80.0 to 0.0. |
fader_bump | address, amount (dB) | Native relative move; positive is louder. Firmware 4.0.4.0+. |
Channel input routing
| Command | Args | Notes |
|---|---|---|
set_input | address, input | Primary input source. |
set_secondary_input | address, input | Secondary (backup) source, or None. |
set_input_fader / set_secondary_input_fader | address, fader | Input gain, -80.0 to 0.0 dB. |
set_input_mode | address, mode | Override (auto override primary) or Backup (signal-sensing override). |
set_mix_fader | address, mixer, fader | One mixer input fader. In circuit only while the primary source is Mixer. |
set_dante_on_ramp | address, mode | What the channel puts back on the Dante network. Dante Connect models only. |
Channel output configuration
| Command | Args | Notes |
|---|---|---|
set_channel_name | address, name | The channel name stored in the amplifier. |
set_output_mode | address, mode | LoZ, HiZ-70V or HiZ-100V. Check the speaker wiring first. |
set_hiz_hpf | address, frequency | Hi-Z high-pass, 35 to 5000 Hz. |
Load monitoring and limiters
| Command | Args | Notes |
|---|---|---|
load_monitor_on / load_monitor_off | address | Speaker load monitoring. |
set_load_high_limit / set_load_low_limit | address, limit | Impedance limits in ohms — outside them the load reads Open / Short. |
rms_limiter_on / rms_limiter_off | address | RMS (thermal) limiter. |
set_rms_threshold / set_rms_attack / set_rms_release | address, value | Threshold in volts (10-140), times in ms (1000-10000). |
peak_limiter_on / peak_limiter_off | address | Peak (excursion) limiter. |
set_peak_threshold / set_peak_attack / set_peak_release | address, value | Threshold in volts (14-198), times in ms (1-1000). |
Crossover and EQ
| Command | Args | Notes |
|---|---|---|
set_crossover_gain / set_crossover_delay / set_polarity | address, value | Band gain (-15 to 15 dB), delay (0-100 ms), polarity invert. |
high_pass_on / high_pass_off / low_pass_on / low_pass_off | address | Crossover filter enables. |
set_high_pass_type / set_low_pass_type | address, type | Butterworth, Linkwitz-Riley or Bessel, 6 to 48 dB/oct. |
set_high_pass_frequency / set_low_pass_frequency | address, frequency | 20 to 20000 Hz. |
set_eq_enable / set_eq_type / set_eq_gain / set_eq_frequency / set_eq_q | address, filter, value | One output EQ band. filter is the band number. |
Signal generator and pilot tone
| Command | Args | Notes |
|---|---|---|
signal_generator_channel_on / _off | address | Route the generator into the channel. |
set_signal_generator_fader | address, fader | Generator level into the channel. |
pilot_tone_on / pilot_tone_off | address | Pilot tone supervision. |
set_pilot_tone_frequency | address, frequency | 19000 to 24000 Hz. |
Amplifier-wide
| Command | Args | Notes |
|---|---|---|
auto_standby_on / auto_standby_off | — | Auto standby. |
set_auto_standby_threshold | threshold | -80.0 to 0.0 dBFS. |
set_auto_standby_wait | minutes | 1 to 240. |
set_signal_generator_type / set_signal_generator_frequency | type / frequency | Pink noise, white noise or tone; 20 to 20000 Hz. |
set_input_sensitivity | input, sensitivity | 26dB or 34dB on one physical analog input. |
set_device_name / set_venue_name | name | The amplifier's naming fields. |
Reads and escape hatches
| Command | Args | Notes |
|---|---|---|
get_status | — | Re-read everything: device info, amplifier settings, power supply, every channel. |
get_device_info / get_power_supply | — | One section each. |
get_channel_status | address | One channel's level, mute, enable, faults, input and load state. |
get_meters | — | Output watts, volts and impedance for every channel, once. |
get_element | element | Read any element by URL, e.g. /amp/channels/1/output/fader. |
subscribe_element / unsubscribe_element | element | Subscribe to any element. A commissioning tool — a meter subscription pushes continuously until the connection drops. |
passthrough | command | Send one protocol line verbatim, e.g. set /amp/channels/1/output/mute true. The escape hatch for elements this driver does not model. |
Known quirks
- There is no power command. The amplifier is designed to stay powered, and auto-standby is a
threshold-and-timer setting rather than a switch.
power_on/power_off(and the zoneon/offverbs) drive the channel enable element — the WebUI's "channel ready" control. The amplifier stays on and the channel stops passing audio. Mute is a separate state and those verbs leave it alone. For a true power cut, switch the amplifier's supply with a controllable outlet from the zone'soff_action. - Level is a dB fader, not a percentage. The fader runs -80.0 to 0.0 dB; GEM's 0-100 maps onto
fader_min_db..0 linearly in dB, so 50 is -40 dB and 0 is -80 dB (silent, but not muted). If the bottom half of a slider feels dead, raisefader_min_db. lineWarningdoes not read backwards — the guide does. The protocol guide documents/amp/powerSupply/lineWarningtrueas AC line voltage is OK. Hardware says otherwise: a 168N on a healthy 124 V line reportslineWarning falsewhilepowerOkistrueand no fault is set. The element is a literal warning flag, so the driver inverts it:line_voltage_okistruewhen the line is healthy, which is what an attribute trigger on it should assume.bumpneeds firmware 4.0.4.0.volume_up/volume_downdeliberately do not use it — they compute the new fader from the subscribed level and write it absolutely, which works everywhere.fader_bumpis the native relative move and is the one that needs the newer firmware.- Input sources differ by model. Network Connect amplifiers have analog inputs only, and only as many as they have channels — a 354 has no Analog 5-8. Dante Connect amplifiers expose all eight Dante inputs regardless of channel count. The driver offers the full list and lets the amplifier reject what it does not have.
- Clip and limiting are transient, not state. They are read once on connect and subscribed only
when
subscribe_protectionis set, so the default is quiet on a system being driven hard. They are always included inget_channel_status. - Mix faders are only in circuit while the channel's primary input source is
Mixer. - The protocol has no grouping of any kind. There is no group, gang, stereo-link, zone, preset
or master-fader element, no way to address more than one channel in a line, and no wildcard —
/amp/channels/1,2/...,/amp/channels/*/...and every spelling of a group URL are refused with object/element does not exist. The address space is flat and leaf-only: a branch URL such as/amp/channels/1or/amp/deviceInfois not readable either, so the amplifier cannot be enumerated over the API — you can only read elements you already know the name of. Group channels on the GEM side (one zone per channel, gathered by a macro, a UI zone list, or an AV zone that spans them), not on the amplifier. - Written from the LEA Open API TCP protocol guide rev 7 (10-10-2025), which notes that more
commands exist than it documents. Use
passthroughfor anything not modelled here. - Verified against a Connect Series 168N on firmware 4.0.4.14: every element this driver models
was read back from the amplifier, and level, mute, channel enable,
mute_toggle,volume_up/volume_down,set_faderandfader_bumpwere driven on it. The amplifier has 8 channels and 8 output EQ bands per channel, numbered from 1. Where the protocol guide and the hardware disagreed, the hardware won — seelineWarningabove.
Troubleshooting
| Symptom | Check |
|---|---|
| Connects but nothing ever updates | Firmware older than 1.1.0.x answers only on the websocket API. Check the version in the WebUI and update the amplifier. |
| Zones exist but commands do nothing | The zone address must be the bare channel number (1, not ch1 or 1:1). The driver logs the address it refused. |
| Volume slider feels dead over its bottom half | The fader is linear in dB, so 50 is -40 dB. Raise fader_min_db to compress the range into the part of the fader the room uses. |
| Channel count wrong, or zones for channels that do not exist | The amplifier reports it on /amp/deviceInfo/numOutputs. If it does not answer, the driver falls back to the highest mapped zone address; set the channels attribute to pin it. |
| Attribute history filling up | meter_poll_interval is set. Per-channel watts and volts move with the programme material — set it back to 0 and use get_meters on demand. |
An error: line in the log naming a rejected command | bump needs firmware 4.0.4.0, and some elements differ between Network Connect and Dante Connect models. The amplifier echoes the line it rejected. |
| Level changes made in the WebUI do not appear | Subscriptions live on the TCP session. If the connection has dropped, the driver re-subscribes on reconnect and rewrites every value. |
Related documentation
- Zones — one zone per amplifier channel, addressed by channel number.
- AV Zones — bind this amplifier as a zone's Volume Device.
- Devices — add and configure the amplifier.
- Commands — the command grid and the Test runner.
- Attributes — the reflected state above, and triggering on it.