USB Extender Node Rename Migration Guide
A guide for third-party integrations (Q-SYS, AMX, Crestron, custom) updating to the new
USB_EXTENDER node and its restructured fields.
- The USB-extender node
typeinget deviceresponses is renamed fromUSB_ICRONtoUSB_EXTENDER. - Several fields inside the node were also restructured, so this is not a pure rename.
Notably, the single-peer scalars (
peer_mac_address,peer_device_id) became apeers[]array, andconfiguration.extender_typebecameconfiguration.role. - The rename is not limited to the node. The
usb_icroncapability flag, theUSB_ICRONrouting stream-type literal (used withswitch/stop), theusb_icronsubscription type, and theicroncommand were all renamed to theirusb_extender/USB_EXTENDERequivalents. - Version timeline: API 3.8 added the
usb_extenderforms and deprecated theusb_icronforms, emitting both nodes in the sameget deviceresponse during the transition. API 3.9 removed theusb_icronnode, capability, stream type, subscription type, and theicroncommand entirely. A 3.9 Control Server only understands theusb_extenderforms. - Recommended approach: prefer the
usb_extenderforms when present, falling back to theusb_icronforms only for Control Servers older than 3.8.
Reason for the change
The SDVoE Control Server has generalized its USB-extender abstraction so that it can describe
extenders built on chipsets other than Icron in the future. The historical USB_ICRON node was
conceptually tied to one specific extender family; the new USB_EXTENDER node is engine-agnostic.
The underlying hardware behavior on currently shipping DVIGear products is unchanged. This is a schema change in the Control Server's reporting and configuration model.
API 3.8 Control Server builds emit both the legacy USB_ICRON node and the new
USB_EXTENDER node side-by-side in every get device response, with the legacy forms
deprecated but still present. API 3.9 removed the legacy USB_ICRON forms entirely, so those
builds emit only USB_EXTENDER. Builds older than 3.8 emit only USB_ICRON. An integration
must tolerate all three states for the life of the deployment: old-only, both, and new-only.
Field-by-field changes
Old (USB_ICRON) | New (USB_EXTENDER) | Change |
|---|---|---|
type = "USB_ICRON" | type = "USB_EXTENDER" | Renamed: node type identifier. |
configuration.extender_type ("LOCAL" | "REMOTE") | configuration.role ("LOCAL" | "REMOTE") | Renamed: same values, new key. |
configuration.program_mode | configuration.program_mode | Unchanged. |
configuration.rs232_port | configuration.rs232_port | Unchanged. |
| — | configuration.peers (array) | New: configurable peer list (for LEX devices). |
status.chip_present | status.chip_present | Unchanged. |
status.mac_address | status.mac_address | Unchanged. |
status.reachable | status.reachable | Unchanged. |
status.revision | status.revision | Unchanged. |
status.ip_mode | status.ip_mode | Unchanged. |
status.ip_address | status.ip_address | Unchanged. |
status.peer_mac_address (string) | (see status.peers[]) | Removed: read from first entry of status.peers[] for the single-peer case. |
status.peer_device_id (string) | (see status.peers[]) | Removed: read from first entry of status.peers[] for the single-peer case. |
status.sui_peers (array) | status.peers (array) | Renamed: each entry still has mac_address and device_id. |
status.link_status_support | status.link_status_support | Unchanged. |
status.linked (boolean) | — | Removed: no direct replacement. Check status.peers[] non-empty plus per-peer state if you relied on this. |
status.sui_enabled | status.sui_enabled | Unchanged. |
| — | status.chipset_type (e.g. "ICRON") | New: identifies the underlying extender chipset ("ICRON" on current hardware). |
| — | status.role (duplicates configuration) | New: convenience copy of configuration.role. |
JSON shape
Before (legacy USB_ICRON node)
{
"type": "USB_ICRON",
"index": 0,
"configuration": {
"extender_type": "LOCAL",
"program_mode": "NONE",
"rs232_port": 0
},
"status": {
"chip_present": true,
"mac_address": "6cdffb011b10",
"reachable": true,
"revision": "1.9.4",
"ip_mode": "DHCP",
"ip_address": "192.168.1.132",
"peer_mac_address": "",
"peer_device_id": "",
"link_status_support": true,
"linked": false,
"sui_enabled": true,
"sui_peers": []
},
"inputs": []
}
After (new USB_EXTENDER node)
{
"type": "USB_EXTENDER",
"index": 0,
"configuration": {
"role": "LOCAL",
"program_mode": "NONE",
"rs232_port": 0,
"peers": []
},
"status": {
"chipset_type": "ICRON",
"chip_present": true,
"mac_address": "6cdffb011b10",
"reachable": true,
"revision": "1.9.4",
"ip_mode": "DHCP",
"ip_address": "192.168.1.132",
"link_status_support": true,
"sui_enabled": true,
"peers": [],
"role": "LOCAL"
},
"inputs": []
}
When parsing the nodes[] array returned by get device, expect both a USB_ICRON node
and a USB_EXTENDER node to appear in the same response on modern Control Servers. They
describe the same underlying hardware extender. Pick one and parse it consistently,
preferring USB_EXTENDER when present.
Companion renames (beyond the node)
The node rename came with matching renames across the rest of the USB-extender surface. As with
the node, the usb_extender forms were added in API 3.8 and the usb_icron forms were
removed in API 3.9.
| Old form (≤ 3.8) | New form (3.8+) | Notes |
|---|---|---|
capabilities.usb_icron (Boolean) | capabilities.usb_extender (Boolean) | Indicates the device has a USB 2.0 extender. |
USB_ICRON stream-type literal (switch / stop) | USB_EXTENDER stream-type literal | e.g. switch <src>:USB_EXTENDER:0 <dst>:0, stop <dev> USB_EXTENDER 0. |
usb_icron subscription type | usb_extender subscription type | Used wherever subscriptions are enumerated. |
icron <target> <pair|unpair|reset> … command | usb_extender <target> <pair|unpair|reset> … command | Same subcommands and argument order; only the verb changed. Address devices by their BlueRiver device_id. |
On a 3.9 Control Server the icron command, the usb_icron capability flag, and the USB_ICRON
stream-type and subscription type no longer exist. Using them returns an error
(INVALID_COMMAND / ILLEGAL_ARGUMENT). Send the usb_extender forms instead. They are also
accepted by 3.8 builds, so prefer them whenever the device reports a USB_EXTENDER node.
Unchanged behaviour
| Area | Status |
|---|---|
| USB extender hardware behavior, IP mode, RS-232 programming, etc. | Unchanged. This is a Control Server reporting and command-naming change only. |
| Pairing semantics (LEX ↔ REX, SUI multi-pairing limits) | Unchanged. Only the command verb and identifiers changed. |
Recommended migration strategy
Implement a small accessor layer that hides the dual-shape complexity from the rest of your integration. Three accessors cover the vast majority of usage: locate the node, read the role, read the peers.
Pseudo-code
// 1. Locate the USB extender node, preferring the new node type.
function findUsbExtenderNode(device) {
const nodes = device.nodes || [];
return nodes.find(n => n.type === "USB_EXTENDER")
|| nodes.find(n => n.type === "USB_ICRON")
|| null;
}
// 2. Read the role ("LOCAL" / "REMOTE") with field-name fallback.
function getExtenderRole(node) {
if (!node) return "";
return node.configuration.role
|| node.configuration.extender_type
|| "";
}
// 3. Read the peer list as a normalized array of {mac_address, device_id}.
function getExtenderPeers(node) {
if (!node) return [];
if (Array.isArray(node.status.peers)) return node.status.peers;
if (Array.isArray(node.status.sui_peers)) return node.status.sui_peers;
// Old scalar fields: synthesize a one-entry array if both are populated.
const mac = node.status.peer_mac_address || "";
const did = node.status.peer_device_id || "";
return (mac && did) ? [{ mac_address: mac, device_id: did }] : [];
}
Setting the role (LEX vs REX)
If your integration writes the role via set <device_id> property <path> <value>, the property
path also changes. Use the path that matches the node the Control Server emits:
# Old form (still accepted by old Control Server builds):
set <device_id> property nodes[USB_ICRON:0].configuration.extender_type LOCAL
# New form (accepted by Control Server builds that emit USB_EXTENDER):
set <device_id> property nodes[USB_EXTENDER:0].configuration.role LOCAL
A safe pattern is to issue the set against whichever node type was present in the most recent
get device response for that device.
Q-SYS integration notes
If your Q-SYS plugin is parsing the JSON response of get device in Lua (e.g. via rapidjson
or the Q-SYS JSON library), the porting work is mechanical:
- Wherever you currently iterate
device.nodeslooking fortype == "USB_ICRON", accept"USB_EXTENDER"as well, and prefer it. - Wherever you index into
nodes[USB_ICRON:0].configuration.extender_type, readconfiguration.rolefirst, falling back toconfiguration.extender_type. - Wherever you read
status.peer_mac_addressorstatus.peer_device_iddirectly, switch to reading the first element ofstatus.peers, falling back tostatus.sui_peers, falling back to the scalar fields. - Routing and pairing commands do need to change on API 3.9: use the
USB_EXTENDERstream-type literal withswitch/stop, and theusb_extendercommand in place of the removedicroncommand (same subcommands, only the verb changed). Address devices by their BlueRiverdevice_id, not the extender chip MAC.
Verification checklist
- Against a Control Server that emits the new
USB_EXTENDERnode, your accessor returns the correct role and peers. - Against a Control Server that emits only the legacy
USB_ICRONnode, your accessor still returns the correct role and peers. - Against a Control Server that emits both nodes in the same response, your accessor
consistently uses one (recommended:
USB_EXTENDER) and does not double-count peers. - Pairing a LEX/REX via your existing pair/unpair flow continues to work end-to-end.
- On API 3.9, routing/pairing uses the
usb_extendercommand and theUSB_EXTENDERstream literal addressed bydevice_id; the legacyicron/USB_ICRONforms return errors and are only valid on Control Servers older than 3.9. - If you display the extender peer count in your UI, it stays consistent across a Control Server upgrade.
Questions or issues
If your integration relies on a field not covered above, or you observe a Control Server
response that doesn't fit either shape, please reach out to DVIGear support with a captured
get device response and a description of the integration scenario. We will extend this guide
as needed.
See also
- USB Extender Node: reference for the new node.
- Icron USB Extender Node (legacy): reference for the deprecated node, retained for backward compatibility.
- Full Device Response: example showing both nodes emitted together during the transition.