<!-- GENERATED from docs/api/rialto2100d.yaml (customer tier) by avpro-api's api-spec/apispec.py, using tools/gen_api_docs.py. Do not edit: change the spec and run `apispec.py docs --into-tree`. -->
# ACP-RIALTO-2100D — REST and WebSocket API

**Applies to:** AudioControl ACP-RIALTO-2100D (stereo amplifier with Dante)  
**Interface:** HTTP (REST) on port 80, WebSocket on port 80, path `/ws`  
**API version:** 1  
**Document generated:** 2026-10-30

Machine-readable: [`ACP-RIALTO-2100D_REST_API.openapi.yaml`](ACP-RIALTO-2100D_REST_API.openapi.yaml) (REST, OpenAPI 3.1) and [`ACP-RIALTO-2100D_REST_API.asyncapi.yaml`](ACP-RIALTO-2100D_REST_API.asyncapi.yaml) (WebSocket, AsyncAPI 2.6). The telnet commands are in [`ACP-RIALTO-2100D_API.md`](ACP-RIALTO-2100D_API.md).
## 1. Quick start

```sh
curl http://192.168.1.10/api/v1/info
curl "http://192.168.1.10/api/v1?get=audio.volume"          # {"ok":true,"value":30}
curl "http://192.168.1.10/api/v1?tree=audio"                # the whole audio branch
curl "http://192.168.1.10/api/v1?cmd=SET%20MUTE"             # {"ok":true,"seq":57,"reply":"MUTE"}
curl "http://192.168.1.10/api/v1?get=device.cmdApplied"     # >= 57: the mute has been applied
```
## 2. Model

Every setting and status value is a **node** with a dotted path. The same paths are used by REST, the WebSocket and the settings export file.

| Type | On the wire |
|---|---|
| bool | `true` / `false` |
| int | whole number, range enforced |
| number | JSON number in real units (dB, feet, Q); a value finer than the step is refused, not rounded |
| choice | one of a fixed set of **names** — never an integer |
| text | string |

## 3. REST — `http://<unit>/api/v1`

| Request | Reply |
|---|---|
| `GET /api/v1/info` | `{"api":1,"manufacturer":"AVPro Global Holdings","brand":"AudioControl","product":"ACP-RIALTO-2100D","serial":…,"mac":…,"hostname":…,"mcu":…,"describe":"/api/v1/describe"}` |
| `GET /api/v1/describe` | how the unit is set up: `interfaces` (id → port, state, version, `clients` / `inUse`), `firmware`, `modules` (its Dante module). Anything else under `/api/` is `404` `{"ok":false,"err":"path"}`. See `avpro-api/docs/AVPRO_DESCRIBE.md` |
| `GET /api/v1?get=<path>` | `{"ok":true,"value":…}` |
| `GET /api/v1?tree=<branch>` | `{"ok":true,"value":{…nested…}}` |
| `GET /api/v1?cmd=<telnet command>` | `{"ok":true,"seq":N,"reply":"<what telnet prints>"}` |

Always HTTP 200 with `Access-Control-Allow-Origin: *`; success is `ok`. A reply is at most 2048 bytes, so `?tree=eq` and `?tree=eq.groups` answer `size` — read one level down (`eq.groups.sub`). Send one request at a time.
### Errors

| `err` | Meaning | Do |
|---|---|---|
| `busy` | Command queue short on room (a burst) | wait ~250 ms, resend the same request |
| `dropped` | The full queue refused the command | resend |
| `command` | The parser rejected it; `msg` has its text (`PARAM ERROR: …`, `CMD ERR`) | fix the command |
| `state` | Valid, but refused in the current state — `VOL DEFEATED` (digital input selected with volume defeat on) | nothing queued; do not retry |
| `path` | No such node or branch | |
| `size` | Branch too big for one reply | read a narrower branch |
| `badrequest` | No `get` / `tree` / `cmd` given | |

### Accepted vs applied

A `?cmd=` reply means **accepted**. The unit executes queued commands in order, about 100 ms per DSP step, so a burst takes seconds. Each reply carries `seq`; the read-only node `device.cmdApplied` says every command up to that number — and every follow-up step it triggered — has run:
```js
const r = await (await fetch(`http://${ip}/api/v1?cmd=SET%20VOL%2040`)).json();
// r = {ok:true, seq:212, reply:"VOL 40"}
const applied = a => ((a - r.seq) & 0x7FFFFFFF) < 0x40000000;   // 31-bit, wraps
while (!applied((await (await fetch(`http://${ip}/api/v1?get=device.cmdApplied`)).json()).value))
  await new Promise(t => setTimeout(t, 100));
```
`seq` restarts at 0 when the unit boots (watch `device.uptime` go down). Not covered: work the unit hands to the Dante module or a reboot (`SET TIP`, `SET RBT`). A top-level word the parser does not know prints nothing, so it answers `ok` with an empty `reply`, as on telnet.
## 4. WebSocket — `ws://<unit>/ws`

Push channel for live UIs. On connect the unit sends `{"ev":"hello","api":1,"product":…,"mcu":…}`; subscribe to the branches you show:
```json
{"op":"sub","id":1,"paths":["audio","outputs.channels","device.cmdApplied"]}
```
…and receive `{"ev":"delta","path":"audio.volume","value":31}` whenever a subscribed value changes, whoever changed it. `{"ev":"invalidate","path":"eq"}` means re-read that branch.

| Client sends | Unit answers |
|---|---|
| `{"op":"sub","id":1,"paths":[…]}` / `unsub` | `{"id":1,"ok":true}` |
| `{"op":"get","id":2,"path":"audio"}` | `{"id":2,"ok":true,"value":…}` |
| `{"op":"set","id":3,"path":"audio.mute","value":true}` | `{"id":3,"ok":true,"seq":N}` |
| `{"op":"call","id":4,"path":"eq.flatten"}` | `{"id":4,"ok":true,"seq":N}` |

Refusals: `{"id":3,"ok":false,"err":"range","msg":"audio.volume is 0..100"}` — `err` is one of `path`, `readonly`, `type`, `range`, `state`, `busy`, `dropped`, `size`.
**Limits.** 3 connections per unit (a fourth is refused — fall back to REST polling); 12 subscriptions per connection (subscribe to branches); an idle connection is pinged and dropped if silent. A WebSocket reply is one frame of at most 1400 bytes, smaller than a REST reply, so `calibration`, `eq`, `eq.groups` and `speakerProfile` answer `size` here - `get` one level down.
The same socket also carries the unit's level meters (send `METER ON|OFF`, `DMETER ON|OFF`; frames like `{"meter_outL":"0.012"}`).
**What is pushed.** The *Push* column below: `change` = pushed whenever the value changes by any route; `write` = pushed when written through the API (EQ bands — watch `eq.revision` for other routes); `applied` = pushed as commands complete; `none` = read it when you need it.
## 5. Actions

| Path | Does |
|---|---|
| `system.reboot` | Reboot the unit (after the reply has been sent). |
| `eq.flatten` | Reset every user PEQ band to its default (gains 0). |
| `speakerProfile.flatten` | Clear the speaker-profile PEQ. |
| `speakerProfile.save` | Save the current profile bands as the custom profile. |
| `speakerProfile.loadCustom` | Load the saved custom profile. |

WebSocket `{"op":"call","path":…}`; over REST use the telnet form (`SET RBT`, `SET EQ FLATTEN`).
## 6. Nodes

Access: **RW** = settable (WebSocket `set`, or the telnet command via `?cmd=`), **RO** = read-only.

### `audio`

Main zone - power, volume, mute and the active input.

| Path | Type | Values | Access | Push | Telnet | Description |
|---|---|---|---|---|---|---|
| `audio.power` | bool | `true` / `false` | RW | change | `SET POWER ON`<br>`SET POWER OFF` | Device on (true) or in standby (false). Powering up is not instant - the unit reports on once it is. |
| `audio.mute` | bool | `true` / `false` | RW | change | `SET MUTE`<br>`SET UNMUTE` | Speaker outputs muted. |
| `audio.volume` | int | 0 … 100 | RW | change | `SET VOL <value>` | Speaker volume. While the active input has volume defeat on, changes are refused: err state, msg VOL DEFEATED. |
| `audio.input` | choice | `digital`, `analog`, `dante` | RW | change | `SET INPUT DIGITAL`<br>`SET INPUT ANALOG`<br>`SET INPUT DANTE` | Active audio input. |
| `audio.format.in` | text | text | RO | change | — | Incoming signal as the unit reports it, e.g. "PCM 2.0ch"; empty when there is no signal. |
| `audio.format.out` | text | text | RO | change | — | Output format; empty when idle. |

### `outputs`

Amplifier output - level, distance, crossover, amp mode, test tone.

| Path | Type | Values | Access | Push | Telnet | Description |
|---|---|---|---|---|---|---|
| `outputs.channels.left.level` | number | -12 … 12 (step 0.1) | RW | change | `SET OUT CH GAIN 1 <dB>` | Channel trim in dB, 0.1 dB steps. |
| `outputs.channels.left.distance` | number | 0 … 30 (step 0.1) | RW | change | `SET OUT CH DISTANCE 1 <feet> FEET` | Speaker-to-listener distance in feet, 0.1 ft steps (sets the channel delay). Left/right are refused while bridged: err state. |
| `outputs.channels.left.invert` | bool | `true` / `false` | RW | change | `SET OUT CH INV LEFT ON`<br>`SET OUT CH INV LEFT OFF` | Polarity inverted. |
| `outputs.channels.right.level` | number | -12 … 12 (step 0.1) | RW | change | `SET OUT CH GAIN 2 <dB>` | Channel trim in dB, 0.1 dB steps. |
| `outputs.channels.right.distance` | number | 0 … 30 (step 0.1) | RW | change | `SET OUT CH DISTANCE 2 <feet> FEET` | Speaker-to-listener distance in feet, 0.1 ft steps (sets the channel delay). Left/right are refused while bridged: err state. |
| `outputs.channels.right.invert` | bool | `true` / `false` | RW | change | `SET OUT CH INV RIGHT ON`<br>`SET OUT CH INV RIGHT OFF` | Polarity inverted. |
| `outputs.channels.sub.level` | number | -12 … 12 (step 0.1) | RW | change | `SET OUT CH GAIN SUB <dB>` | Channel trim in dB, 0.1 dB steps. |
| `outputs.channels.sub.distance` | number | 0 … 30 (step 0.1) | RW | change | `SET OUT CH DISTANCE SUB <feet> FEET` | Speaker-to-listener distance in feet, 0.1 ft steps (sets the channel delay). Left/right are refused while bridged: err state. |
| `outputs.channels.sub.mute` | bool | `true` / `false` | RW | change | `SET SUB MUTE`<br>`SET SUB UNMUTE` | Subwoofer output muted (in addition to audio.mute). |
| `outputs.channels.sub.enabled` | bool | `true` / `false` | RW | change | `SET OUT CH SUB SUB`<br>`SET OUT CH SUB NONE` | Sub output in use (false = not connected; the sub is muted). |
| `outputs.crossover.frequency` | int | 40 … 150 | RW | change | `SET OUT FREQ XOVER <value>` | Crossover corner in Hz: the sub low-pass and, with a limited response, the high-pass on the other outputs. |
| `outputs.response` | choice | `limited`, `fullrange` | RW | change | `SET OUT FREQ RESPONSE 1_2 FULLRANGE`<br>`SET OUT FREQ RESPONSE 1_2 LIMITED` | limited = the speakers' bass goes to the sub (high-pass at the crossover); fullrange = no bass is taken from them. |
| `outputs.bridge` | bool | `true` / `false` | RW | change | `SET OUT CH SUB BRIDGE ON`<br>`SET OUT CH SUB BRIDGE OFF` | Sub output bridged. |
| `outputs.testTone.output` | choice | `none`, `left`, `right`, `sub`, `danteLeft`, `danteRight` | RW | change | `SET TEST TONE OUT NONE\|1\|2\|SUB\|DANTEL\|DANTER` | Output playing the pink-noise test tone; none = off. |
| `outputs.testTone.fullband` | bool | `true` / `false` | RW | change | `SET TEST TONE FULLBAND ON`<br>`SET TEST TONE FULLBAND OFF` | Test tone without the 500 Hz high-pass / 2 kHz low-pass band limit. |
| `outputs.dante.volume` | int | 0 … 100 | RW | change | `SET DVOL <value>` | Dante TX volume. While outputs.dante.follow is on it tracks the speaker volume and a direct change is refused: err state, msg DVOL FOLLOW LOCKED. |
| `outputs.dante.mute` | bool | `true` / `false` | RW | change | `SET DMUTE`<br>`SET DUNMUTE` | Dante TX muted. |
| `outputs.dante.follow` | bool | `true` / `false` | RW | change | `SET DVOL FOLLOW ON`<br>`SET DVOL FOLLOW OFF` | Dante TX volume follows the speaker volume. |
| `outputs.dante.txSource` | choice | `input`, `sub` | RW | change | `SET DANTE TX SOURCE SUB`<br>`SET DANTE TX SOURCE INPUT` | What the Dante TX carries: input = the selected input (monitor feed), sub = the subwoofer pre-out. |
| `outputs.dante.channels.left.level` | number | -12 … 12 (step 0.1) | RW | change | `SET OUT CH GAIN DL <dB>` | Dante TX channel trim in dB, 0.1 dB steps. |
| `outputs.dante.channels.left.distance` | number | 0 … 30 (step 0.1) | RW | change | `SET OUT CH DISTANCE DL <feet> FEET` | Dante TX channel delay expressed as distance in feet. |
| `outputs.dante.channels.right.level` | number | -12 … 12 (step 0.1) | RW | change | `SET OUT CH GAIN DR <dB>` | Dante TX channel trim in dB, 0.1 dB steps. |
| `outputs.dante.channels.right.distance` | number | 0 … 30 (step 0.1) | RW | change | `SET OUT CH DISTANCE DR <feet> FEET` | Dante TX channel delay expressed as distance in feet. |

### `inputs`

Input priority and per-input gain, volume defeat and signal sense (digital, analog, Dante).

| Path | Type | Values | Access | Push | Telnet | Description |
|---|---|---|---|---|---|---|
| `inputs.priority` | choice | `none`, `digital`, `analog`, `dante` | RW | change | `SET PRIORITY NONE\|DIGITAL\|ANALOG\|DANTE` | Input the signal sense switches to first when several have signal. |
| `inputs.{input}.gain`<br><sub>input = digital, analog, dante</sub> | choice | `low`, `med`, `high` | RW | change | `SET INPUT GAIN DIGITAL\|ANALOG\|DANTE LOW\|MED\|HIGH` | Input gain offset: low = normal, med = +3 dB, high = +6 dB. |
| `inputs.{input}.volumeDefeat`<br><sub>input = digital, analog, dante</sub> | bool | `true` / `false` | RW | change | `SET VOL DEFEAT DIGITAL\|ANALOG\|DANTE ON\|OFF` | Fixed volume for this input: while it is active, volume commands are refused. |
| `inputs.{input}.signalSense`<br><sub>input = digital, analog, dante</sub> | bool | `true` / `false` | RW | change | `SET SIGNAL SENSE DIGITAL\|ANALOG\|DANTE ON\|OFF` | Switch to this input automatically when signal appears on it. |
| `inputs.{input}.source`<br><sub>input = dante</sub> | text | text | RW | change | `SET DANTE INPUT <channel>@<device>`<br>`SET DANTE INPUT NONE` | Dante 1 In's source, as <channel>@<device> (e.g. Sub/LFE@AXIS16-020adc). Setting it routes Dante 1 In, and Dante 2 In too while inputs.dante.link is true. "" = not routed, "mixed" = the two channels differ (read the channels). Setting "" clears the route. The choices are GET /api/v1/inputs/dante/sources: every Dante TX channel found on the network, AVPro devices first. Routes are stored in the Dante module and survive reboots. |
| `inputs.{input}.status`<br><sub>input = dante</sub> | text | text | RO | change | — | State of that route as the Dante module reports it: dynamic / static = the flow is up (the web UI shows 'Route ok'), none = not routed, unresolved = source not on the network, in_progress, an error name, mixed = the two channels differ, or unknown before the module has answered. |
| `inputs.{input}.sourceCount`<br><sub>input = dante</sub> | int | counter | RO | change | — | Number of Dante devices in the source list; it changes when that list does, so a client subscribed to it knows when to fetch GET /api/v1/inputs/dante/sources again. |
| `inputs.{input}.channels.1.source`<br><sub>input = dante</sub> | text | text | RW | change | `SET DANTE INPUT 1\|2 <channel>@<device>`<br>`SET DANTE INPUT 1\|2 NONE` | Source of Dante 1 In or Dante 2 In, as <channel>@<device>; "" = not routed. Channel 2 cannot be set while inputs.dante.link is true (PARAM ERROR). |
| `inputs.{input}.channels.1.status`<br><sub>input = dante</sub> | text | text | RO | change | — | State of that channel's route: dynamic / static = flow up, none, unresolved, in_progress, an error name, or unknown. |
| `inputs.{input}.channels.2.source`<br><sub>input = dante</sub> | text | text | RW | change | `SET DANTE INPUT 1\|2 <channel>@<device>`<br>`SET DANTE INPUT 1\|2 NONE` | Source of Dante 1 In or Dante 2 In, as <channel>@<device>; "" = not routed. Channel 2 cannot be set while inputs.dante.link is true (PARAM ERROR). |
| `inputs.{input}.channels.2.status`<br><sub>input = dante</sub> | text | text | RO | change | — | State of that channel's route: dynamic / static = flow up, none, unresolved, in_progress, an error name, or unknown. |

### `system`

Power-on behaviour, volume limit, auto power-off, IR, front display, status.

| Path | Type | Values | Access | Push | Telnet | Description |
|---|---|---|---|---|---|---|
| `system.volume.powerOn` | int | 0 … 100 | RW | change | `SET ON VOL <value>` | Speaker volume at power-on. |
| `system.volume.limit` | int | 10 … 100 | RW | change | `SET MAX VOL <value>` | Maximum speaker volume; the volume scale is mapped onto it. |
| `system.powerOnState` | choice | `last`, `on`, `off` | RW | change | `SET POWER RECOVERY ON`<br>`SET POWER RECOVERY OFF`<br>`SET POWER RECOVERY LAST` | State after mains power returns. |
| `system.offTimer` | int | 0 … 10080 | RW | change | `SET POWER OFF TIMER <h>H<m>M`<br>`SET POWER OFF TIMER NEVER` | Auto power-off after this many minutes without signal; 0 = never. |
| `system.ir.keyset` | choice | `standard`, `reserved`, `bijou` | RW | change | `SET IR KEYSET <value>` | IR remote code set. |
| `system.ir.front` | bool | `true` / `false` | RW | change | `SET IR FRONT ON`<br>`SET IR FRONT OFF` | Front-panel IR receiver enabled. |
| `system.display.on` | bool | `true` / `false` | RW | change | `SET LCD ON`<br>`SET LCD OFF` | Front display on. |
| `system.display.timeout` | int | 0 … 255 | RW | change | `SET LCDTIMER <value>` | Seconds until the display dims; 0 = stays on. |
| `system.trigger` | bool | `true` / `false` | RO | change | — | 12 V trigger input present. |

### `eq`

User PEQ - 8 bands per output group.

| Path | Type | Values | Access | Push | Telnet | Description |
|---|---|---|---|---|---|---|
| `eq.enabled` | bool | `true` / `false` | RW | change | `SET PEQ ENABLE`<br>`SET PEQ DISABLE` | User PEQ on. |
| `eq.preset` | int | 1 … 3 | RW | change | `SET EQ PRESET <1\|2\|3>` | Active EQ preset, 1-3. A preset holds the EQ of every output group and the speaker-profile state (speaker-PEQ bands, preamps, custom-curve names, built-in profile numbers); the eq.enabled and speakerProfile enable switches are not part of it. The live settings are the active preset - edits stay in it. Setting another number stores the live settings into the active preset and loads the chosen one (about a second). A preset that was never stored keeps the current settings. |
| `eq.presets.1.name` | text | text | RW | change | `SET EQ PRESET NAME <1\|2\|3> <name>` | Name of EQ preset 1-3 (default Preset 1..3): 1-20 printable characters, no double quote, case kept. |
| `eq.presets.2.name` | text | text | RW | change | `SET EQ PRESET NAME <1\|2\|3> <name>` | Name of EQ preset 1-3 (default Preset 1..3): 1-20 printable characters, no double quote, case kept. |
| `eq.presets.3.name` | text | text | RW | change | `SET EQ PRESET NAME <1\|2\|3> <name>` | Name of EQ preset 1-3 (default Preset 1..3): 1-20 printable characters, no double quote, case kept. |
| `eq.groups.{group}.bands.{band}.gain`<br><sub>group = left, right, sub, danteLeft, danteRight; band = 0–7</sub> | number | -12 … 12 (step 0.1) | RW | change | `SET OUT CH PEQ 1\|2\|SUB\|DL\|DR <band> <gain> <freq> <q>` | Band gain in dB. |
| `eq.groups.{group}.bands.{band}.freq`<br><sub>group = left, right, sub, danteLeft, danteRight; band = 0–7</sub> | int | 5 … 20000 | RW | change | `SET OUT CH PEQ 1\|2\|SUB\|DL\|DR <band> <gain> <freq> <q>` | Band centre / corner frequency in Hz (sub group: up to 250 Hz). |
| `eq.groups.{group}.bands.{band}.q`<br><sub>group = left, right, sub, danteLeft, danteRight; band = 0–7</sub> | number | 0.1 … 20 (step 0.001) | RW | change | `SET OUT CH PEQ 1\|2\|SUB\|DL\|DR <band> <gain> <freq> <q>` | Band Q (0.1 to 20; shelves ignore it). |
| `eq.groups.{group}.bands.{band}.type`<br><sub>group = left, right, sub, danteLeft, danteRight; band = 0–7</sub> | choice | `lowshelf`, `peak`, `highshelf` | RO | change | — | Band shape, fixed per band: band 0 low shelf, band 7 high shelf, 1-6 peaking. |

### `speakerProfile`

Speaker-profile PEQ - a profile from the built-in library (or a custom one), 10 bands per channel.

| Path | Type | Values | Access | Push | Telnet | Description |
|---|---|---|---|---|---|---|
| `speakerProfile.enabled` | bool | `true` / `false` | RW | change | `SET SP PEQ ENABLE`<br>`SET SP PEQ DISABLE` | Speaker-profile PEQ on. |
| `speakerProfile.lr.index` | int | -1 … 2398 | RW | change | `SET SP PROFILE <index>`<br>`SET SP PROFILE LR\|SUB NONE` | Profile from the built-in library, by index; -1 = none or a custom profile. Setting an index loads that profile (it applies to the profile's own target, L/R or sub). |
| `speakerProfile.lr.name` | text | text | RO | change | — | Name of the loaded profile. |
| `speakerProfile.lr.preamp` | number | -30 … 30 (step 0.1) | RW | change | `SET SP PEQ PREAMP LR\|SUB <dB>` | Pre-amp gain in dB applied with the profile. |
| `speakerProfile.sub.index` | int | -1 … 2398 | RW | change | `SET SP PROFILE <index>`<br>`SET SP PROFILE LR\|SUB NONE` | Profile from the built-in library, by index; -1 = none or a custom profile. Setting an index loads that profile (it applies to the profile's own target, L/R or sub). |
| `speakerProfile.sub.name` | text | text | RO | change | — | Name of the loaded profile. |
| `speakerProfile.sub.preamp` | number | -30 … 30 (step 0.1) | RW | change | `SET SP PEQ PREAMP LR\|SUB <dB>` | Pre-amp gain in dB applied with the profile. |
| `speakerProfile.channels.{channel}.bands.{band}.type`<br><sub>channel = left, right, sub; band = 0–9</sub> | choice | `peak`, `lowShelf`, `highShelf` | RW | change | `SET SP PEQ L\|R\|SUB <band> PK\|LS\|HS <freq> <q> <gain>` | Band shape. |
| `speakerProfile.channels.{channel}.bands.{band}.freq`<br><sub>channel = left, right, sub; band = 0–9</sub> | int | 0 … 20000 | RW | change | `SET SP PEQ L\|R\|SUB <band> PK\|LS\|HS <freq> <q> <gain>` | Band frequency in Hz; 0 = band off. |
| `speakerProfile.channels.{channel}.bands.{band}.q`<br><sub>channel = left, right, sub; band = 0–9</sub> | number | 0 … 20 (step 0.001) | RW | change | `SET SP PEQ L\|R\|SUB <band> PK\|LS\|HS <freq> <q> <gain>` | Band Q (shelves ignore it). |
| `speakerProfile.channels.{channel}.bands.{band}.gain`<br><sub>channel = left, right, sub; band = 0–9</sub> | number | -30 … 30 (step 0.1) | RW | change | `SET SP PEQ L\|R\|SUB <band> PK\|LS\|HS <freq> <q> <gain>` | Band gain in dB. Writing a band makes the profile custom (index -1). |

### `device`

Identity and firmware version. Read-only.

| Path | Type | Values | Access | Push | Telnet | Description |
|---|---|---|---|---|---|---|
| `device.model` | text | text | RO | change | — | Product model. |
| `device.hostname` | text | text | RW | change | `SET HOSTNAME <name> (no name = back to the default)` | Network hostname (mDNS, DHCP option 12, SNMP sysName, LLDP System Name). Writable: 1-32 letters, digits and hyphens, no hyphen first or last - anything else is refused (err range, with the reason) and nothing changes. "" returns to the default, MODEL-<last 3 MAC bytes>. Applies immediately; survives a reboot; factory reset returns to the default. An SNMP SET of sysName renames the unit the same way. |
| `device.name` | text | text | RO | change | — | Same value as device.hostname (read-only), kept for clients written against the first Rialto API. |
| `device.serial` | text | text | RO | change | — | Serial number. |
| `device.mac` | text | text | RO | change | — | Control-network MAC address. |
| `device.mcuVersion` | text | text | RO | change | — | Firmware version (the DSP program is part of it). |
| `device.bootVersion` | text | text | RO | change | — | Bootloader version. |
| `device.uptime` | int | counter | RO | change | — | Seconds since boot. A value that goes DOWN means the unit rebooted. |
| `device.cmdApplied` | int | counter | RO | change | — | Every command with a seq up to this number has been executed, including any follow-up steps it triggered. Pushed over the WebSocket. |

### `network`

Control and Dante network configuration as currently in effect. Read-only.

| Path | Type | Values | Access | Push | Telnet | Description |
|---|---|---|---|---|---|---|
| `network.dhcp` | bool | `true` / `false` | RO | change | — | Control network uses DHCP. |
| `network.ip` | text | text | RO | change | — | Control network address in effect. |
| `network.mask` | text | text | RO | change | — | Control network subnet mask in effect. |
| `network.gateway` | text | text | RO | change | — | Control network gateway in effect. |
| `network.static.ip` | text | text | RO | change | — | Configured static control-network setting (used when DHCP is off). |
| `network.static.mask` | text | text | RO | change | — | Configured static control-network setting (used when DHCP is off). |
| `network.static.gateway` | text | text | RO | change | — | Configured static control-network setting (used when DHCP is off). |
| `network.tcpPort` | int | counter | RO | change | — | Telnet control port. |
| `network.dante.dhcp` | bool | `true` / `false` | RO | change | — | Dante network uses DHCP. |
| `network.dante.ip` | text | text | RO | change | — | Address the Dante module reports (empty until the unit has queried it - the query runs while the unit is powered on). |
| `network.dante.mask` | text | text | RO | change | — | Subnet mask the Dante module reports. |
| `network.dante.gateway` | text | text | RO | change | — | Gateway the Dante module reports. |
| `network.dante.static.ip` | text | text | RO | change | — | Configured static Dante setting (used when Dante DHCP is off). |
| `network.dante.static.mask` | text | text | RO | change | — | Configured static Dante setting (used when Dante DHCP is off). |
| `network.dante.static.gateway` | text | text | RO | change | — | Configured static Dante setting (used when Dante DHCP is off). |
