Skip to main content

Remotes

The Remotes page manages IP-based remote controls (such as Control4 SR-260, URC, Elan, and compatible devices), mapping remote button presses to GEM commands, macros, AV source selections, and source-specific command maps.

Remote Selection

At the top of the page is a SelectSearch dropdown listing all configured remotes. When editing a remote, the header shows the remote ID and name. For the master template, the header shows "Master Template".

ButtonDescription
ReloadReloads the selected remote's device driver. For the master template (ID 0), this reloads all remotes and shows a confirmation prompt with the count of affected remotes. The button label changes to "Reload All" when the master template is selected.
AddCreates a new remote. Prompts for a name, then creates the remote with pass-through enabled and a placeholder address of 0.0.0.0.
DeleteDeletes the selected remote (with confirmation). Cannot delete the master template.

Master Template (Remote ID 0)

Remote ID 0 is the master template. All other remotes inherit key mappings from this template. When the master template is selected, a yellow info box explains:

  • This is the master template remote.
  • All other remotes inherit default settings from this template.
  • Only configuration settings and key mappings can be edited.

The master template has these restrictions:

  • The Name field is disabled.
  • The AV Zone field is disabled (the template does not control a specific zone).
  • The Enabled toggle is disabled (the template is always enabled).
  • The IP Address and Port fields are disabled.
  • The Delete button is blocked with an error message.
  • The template cannot be deleted.

For the master template, the AV Source list shows all distinct AV sources across all zones, rather than sources for a specific zone.


Remote Configuration

This section appears after selecting a remote from the dropdown.

FieldDescription
NameThe remote's unique identifier (e.g., living_room_remote). Disabled for the master template.
AV ZoneThe AV zone this remote controls. Determines which sources are available for source-type key actions. Disabled for the master template. When changed, the available source list updates.
StatusToggle switch to enable or disable the remote. Shows "Remote is enabled" or "Remote is disabled." Disabled for the master template (always enabled).

Connection Settings

FieldDescription
IP AddressThe IP address of the physical remote control. Disabled for the master template.
Don't monitor connectionA checkbox below the IP Address field. When checked, GEM does not monitor whether this remote is reachable. Useful for remotes that are intermittently powered or rarely used.
PortA dropdown with the following options: Websocket (Auto) (default, no port specified), 6333, 6334, 6335, 6336, 6337, 6338, 6339. Disabled for the master template.
Pass ThroughA toggle switch. When enabled, all unhandled key presses from the remote are passed through to GEM as commands on the currently active AV source (or multiview source, if set). When disabled, only explicitly mapped keys trigger actions. For the master template, this sets the default pass-through behavior for all remotes. See Pass-Through Commands below.
Volume StepA number input (range 1-5) that controls how much the volume changes per press of the volume up/down buttons. For the master template, this sets the global default. For individual remotes, leave blank to use the global value, or enter a number to override it.

Click Save Remote to save the configuration.

The IP address is the remote's identity

A key press is matched to a remote row by the caller's address, so that address decides which remote's key mappings and AV zone the press is handled with. Give every remote a static DHCP reservation — an address that drifts stops matching its row, and one that lands on another remote's address is handled as that remote.

GEM takes the address from the network connection itself and ignores a client-supplied x-forwarded-for header by default, so nothing on the network can claim to be a remote by asserting its address. If you front the Remote Proxy listener with a reverse proxy, name the proxy in trusted_proxies under Server → Network → Reverse proxies so the forwarded address is honored from it.


Tabs

When a remote is selected, the configuration is organized into two tabs:

  • Settings: Remote configuration and connection settings (described above)
  • Keys: Live key events and key mappings (described below)

Key Mappings

The Keys tab shows all button-to-action assignments for the selected remote.

Key Mapping Grid

The grid has the following columns:

ColumnDescription
(delete icon)For remote-specific keys, a delete icon to remove the mapping (with confirmation). For inherited keys, shows an "inherited" link instead — click it to switch the page to the master template, where the key is defined and can be changed.
KeyThe button name (e.g., power, volume_up, play).
ActionThe action type (command, macro, source, multiview_source, or map).
DetailA description of what the action does (e.g., device name and command, macro name, source name, or mapped commands with their sources). When the action resolves to a single entity, the name is a link that opens that macro or device in a reference modal over this page — so checking what a key actually does doesn't cost you the selected remote, the current tab, or the live key log. Command arguments are shown after the link as plain text. map actions name several sources and so are not linked.
EnabledA toggle switch to enable or disable the key mapping. Toggling this saves the change immediately. For inherited keys, shows "always" instead (inherited keys are always enabled).
(edit icon)For remote-specific keys, an edit icon to load the key mapping into the input row for editing. Not available for inherited keys.

Inherited Keys

When viewing a regular remote (not the master template), keys from the master template that are not overridden by this remote appear in the list with reduced opacity and italic text. These inherited keys:

  • Cannot be deleted from this remote (they belong to the master template).
  • Cannot have their enabled state toggled from this remote.
  • Show "inherited" in the delete column and "always" in the enabled column. The "inherited" text is a link that selects the master template in place — the only remote where the key can be edited or deleted.
  • Are automatically overridden if you create a key mapping with the same key name on this remote.

Adding and Editing Key Mappings

The bottom of the key mappings section has an input row for adding or editing mappings:

FieldDescription
KeyA fill-in SelectSearch dropdown with all standard remote button names. You can select from the list or type a custom key name.
ActionA dropdown with five options: command, macro, source, multiview source, map.
Action DetailChanges based on the selected action type (see below).
EnabledA toggle switch (defaults to enabled).
Add / UpdateButton to save the key mapping. Shows "Update" when editing an existing key, "Add" when creating a new one.
CancelAppears when editing. Cancels the edit and clears the input row.

To edit an existing key mapping, click the edit icon in its row. The key's current settings are loaded into the input row, and the button changes to "Update". The row being edited is highlighted with a blue left border.

Bulk key mapping with the AI Assistant

Commissioning a handheld with dozens of mapped buttons is many add/edit cycles on this page. When the AI Assistant is enabled, you can instead describe the whole layout ("map the activity buttons on the theater remote to the Movie, Music, Off, and All On macros") — its bulk_create_remote_keys skill validates every key, macro, device command, and source up front, writes the set in one atomic call, and reloads the remote so the mappings take effect immediately. Existing keys are skipped unless you ask it to overwrite them. The rare source-conditional map action is not supported there — wire those by hand here.

Key mappings are capability grants

A mapped key dispatches the action stored on it exactly as authored, without re-checking the presser's authority against the target — the binding is the integrator's configuration, including any inline address argument. Binding a key to a command on an elevated device, or to an elevated macro, therefore hands that action to anyone using the remote; the editor shows a warning when such a binding is saved. This applies only to mapped keys — a JSON payload that names its own zone, device or macro is judged by the caller, as described below. See Elevated devices and macros.

Action Types

Command

Sends a device command when the key is pressed. When selected, a Command Configuration panel appears below the key mappings section with the full CommandStep component. This lets you select a device, command, and arguments to send.

The detail column shows the device name, command name, and any arguments.

Macro

Runs a GEM macro when the key is pressed. A SelectSearch dropdown appears in the action detail area listing all enabled macros.

The detail column shows the macro name.

Source

Selects an AV source in the remote's AV zone when the key is pressed. A SelectSearch dropdown appears listing all sources for the remote's AV zone, plus an "Off" option (source ID 0) to turn off the zone.

The detail column shows the source device name, or "off" for the Off option.

Multiview Source

Selects a source within the active multiview layout for the remote's AV zone. When the key is pressed, the specified source is displayed in the multiview — either in its grid position or in fullscreen mode, depending on the configuration.

A SelectSearch dropdown appears listing all sources for the remote's AV zone. Select the source to activate within the multiview.

The detail column shows the multiview source device name.

Map

Creates a source-specific command mapping. This action type lets a single key behave differently depending on which AV source is currently active. When selected, two fields appear:

FieldDescription
CommandA text input for the command name to send (e.g., play, pause, home).
SourcesA MultiSelector showing all sources for the zone (plus an "All" option). Select one or more sources that this command applies to.

When the key is pressed, GEM checks which source is currently active in the zone and sends the mapped command only if the active source is in the selected sources list.

If a key already has a map action, adding another map entry for the same key appends to the existing map rather than replacing it. This lets you define different commands for different source groups on the same key.

The detail column shows each command name and which sources it applies to (e.g., play for Apple TV, Roku).

Available Key Names

The following standard key names are available:

  • Power: power
  • Activities: activity_1 through activity_8
  • Letters: a, b, c, d
  • Navigation: up, down, left, right, select, back, exit, menu, guide, info
  • Playback: play, pause, play_pause, stop, record, fast_forward, rewind, scan_back, scan_forward, skip_back, skip_forward, previous
  • Volume/Channel: volume_up, volume_down, mute, channel_up, channel_down
  • Number Pad: 0 through 9, asterisk, enter
  • Color Buttons: red, green, yellow, blue

You can also type a custom key name if the remote sends non-standard keys.


JSON Command Format

Remotes can send a JSON payload instead of a plain key name, allowing parameters to travel with the command. The remote transmits a string like:

{"command": "play", "param1": "chapter_3", "param2": "5"}

GEM parses the payload, uses the command field as the key name (so normal mapping still applies), and captures param1..param10 for downstream use.

Built-in JSON commands

CommandParameters
sourceparam1 = source ID to select on the remote's AV zone
source_slotparam1 = source slot (1–19); GEM resolves the slot to a device through the remote's stored slot map. Baked into spare buttons in generated RTI programs — a slot nothing occupies is a no-op.
multiview_sourceparam1 = source ID, param2 = "true"/"false" for fullscreen
light_sceneparam1 = bright, soft, or off — runs the matching auto light scene against the remote's mirrored UI: every enabled light zone in the UI's scope at level 100/50/0. Membership is resolved on the controller at press time, so lights added later are covered without a re-download. Baked into lighting pages in generated RTI programs; the UI's explicit scenes are macros and arrive over the macro path instead.
shade_sceneparam1 = open, half, close, or stop — runs the matching auto shade scene against the remote's mirrored UI: every enabled zone of a shade, blind or drape subsystem in the UI's scope. Subsystems whose device has a level command take level 100/50/0; the rest take the plain open/close/stop verb, and half is always a level. Both the membership and the level-versus-verb choice resolve on the controller at press time, so a shade added later is covered without a re-download. Baked into shade pages in generated RTI programs; the UI's explicit shade scenes are macros and arrive over the macro path instead.
keypad_buttonparam1 = Lutron button ID, param2 = Lutron processor device ID (optional) — presses that button on the physical control station, the same call the Lutron Keypad widget makes. The processor is a hint: a site with one lutron_qsx device resolves without it, and a stale ID falls back to the site's processor rather than failing, because replacing a processor does not move the keypads on the wall. Baked into lighting pages in generated RTI programs when the mirrored UI carries a control station. Press only — there is no hold form.
subsystem_offparam1 = subsystem ID (a subsystem name or type also resolves) — turns off every enabled zone of that subsystem in the remote's mirrored UI. Lighting subsystems get level 0, the same thing the lights view sends; everything else gets the plain off verb. Membership resolves on the controller at press time, like light_scene, so a zone added to the subsystem later is covered without a re-download. Baked into the power page in generated RTI programs. Acts on the UI rather than the remote's AV zone, so it works on a remote with no AV zone bound.
power_offno parameters — clears the remote's AV zone (source 0), the same thing the Power key does. Baked into the power page's AV Off button in generated RTI programs.
hellodriver, version, generation — sent by the GEM Automation RTI driver (2.1+) on connect. GEM records the reported program generation (visible as the remote's program_generation attribute), logs a stale-program warning if it doesn't match the last generated program, and answers with a manifest. An empty generation report is treated as unknown, never stale — hand-built programs carry no stamp, and Integration Designer's compiler can drop the hidden stamp from a generated program.

Explicit Zone or Device Target

A JSON payload may include an explicit target. When present, GEM forwards the command directly to that zone or device, bypassing the AV-zone pass-through path entirely (so it does not route to the active source device).

FieldDescription
zone_id or zoneNumeric zone ID or zone name to target.
device_id or deviceNumeric device ID or device name to target.

Example payloads:

{"command": "open", "zone_id": 87}
{"command": "on", "zone": "front_porch_lights", "level": 80}
{"command": "play", "device_id": 42}

Any additional fields in the payload are passed through to the command as arguments. Key mappings on the remote are not consulted for these explicit-target payloads.

Two zone-target commands are computed on the controller rather than forwarded: setpoint_up and setpoint_down (e.g. {"command": "setpoint_up", "zone_id": 90}) step the zone's setpoint by one degree from its current values, mirroring the UI's climate control — a remote has no numeric setpoint state of its own to add to. Dual-setpoint zones move the side their mode selects (auto moves both, staggered); single-setpoint zones clamp to the zone's min/max. Generated RTI climate pages use exactly this shape.

Elevated targets over this path

Because the payload names the zone or device itself rather than going through the remote's key mappings, it is never treated as elevated, on any transport. A target flagged Elevated — the device, or the zone itself — is refused, and a raw address argument is confined to outputs mapped on the target device.

This holds even for a physical remote on the TCP/serial listener or the remote-proxy driver. The transport says who is connected; it does not make a zone id lifted out of a payload into your configuration. To drive an elevated target from a remote, map the key to it — a key mapping is your configuration and carries the remote's authority (see Action Types above).

A refused command emits a key_press event with action: error and detail: not authorized, and nothing runs. See Elevated devices and macros.

Explicit Macro Invocation

A JSON payload may invoke a macro directly. When present, GEM runs the macro and bypasses the AV-zone pass-through path.

FieldDescription
macro_idNumeric macro ID to run.
macroMacro name (or numeric ID) to run. A string is looked up by name first, then by ID; a number ({"macro": 7}) is an ID and only ever resolves as one.
argsOptional object passed as arguments to the macro.

Example payloads:

{"macro_id": 42}
{"macro": "good_night"}
{"macro": "scene_recall", "args": {"scene": "movie"}}

If the macro cannot be resolved, a key_press event with action: error and detail: unknown macro is emitted and the command is dropped.

A numeric macro used to be tried against the name table on its way to the ID table, so a macro named 7 would answer {"macro": 7}. It no longer can, in this payload or in a Macro key binding written the same way, and a macro name that is only digits can no longer be created either — see Macros → Creating a Macro. Bindings that name their macro as a string are unchanged.

Elevated macros over this path

Because the payload names the macro itself rather than going through the remote's key mappings, a macro flagged Elevated is always refused here, on every transport — including a physical remote on the TCP/serial listener or the remote-proxy driver. The caller chose the macro id, so the check does not defer to how the caller connected.

To run an elevated macro from a remote, map it to a key using the Macro action type. That mapping is your configuration rather than the caller's, so it carries the remote's authority the way a wall keypad does.

A refused invocation emits a key_press event with action: error and detail: not authorized, and nothing runs. The log line names the macro and says to bind it to a key instead. See Elevated devices and macros.

Pass-Through Commands

When Pass Through is enabled and a key is unmapped, GEM sends the command to the active AV source (or active multiview source). If the command was supplied in JSON form with paramN fields, those values are forwarded as arguments to the driver command, mapped positionally to the target command's declared argument names:

  • param1 → first argument, param2 → second, and so on (up to param10)
  • If the target command has no declared args, the raw param1..paramN keys are passed through unchanged

This lets a single remote button carry data (channel number, chapter, preset, etc.) to the active source without defining a separate key mapping per value.


Status Updates

GEM pushes state back to a connected remote so its buttons can reflect what the zone is actually doing. Updates are sent as newline-delimited JSON to the remote's open connection whenever the relevant AV zone attribute changes:

{"variables": {"rti_source": 2}}
{"variables": {"volume": 45}}
{"variables": {"mute": true}}
{"variables": {"zone_state_3": true}}
{"variables": {"nowplaying": "Bohemian Rhapsody"}}
{"variables": {"artist": "Queen"}}
{"variables": {"playing": true}}

A source change carries the zone's AV state alongside the slot: the source name, and the volume and mute state when the zone reports them ({"variables": {"rti_source": 2, "sourcename": "Roku", "volume": 45, "mute": false}}), so activating a source lands everything on the remote in one message. The standalone volume and mute updates only fire when the stored value actually moves, and a remote whose variable state went stale (a processor that rebooted while the zone was off) would otherwise light the source button and leave the rest of the display where it was. sourcename is the zone's AV source label, falling back to the device label, and is empty when the zone is off. mute reads the zone's mute_state attribute through its on/off vocabulary (booleans are accepted too), both here and in the manifest snapshot.

Media metadata is forwarded whichever way the zone's driver spells it — track, track_title, or now_playing become nowplaying; artist or track_artist become artist; play_state / playback_state collapse to the playing boolean (transport states like PLAYING and TRANSITIONING count as playing). Bind text objects to the driver's Now Playing and Artist variables in Integration Designer and they update live.

Room climate rides along too: temperature and setpoint changes on the remote's climate zone are pushed as driver variables of the same names (driver 2.3+ declares them). The pushed setpoint is the one the zone displays: the plain setpoint when the zone reports one, otherwise the side its mode selects (heat mode shows the heat setpoint, everything else the cool side) — so a cool_setpoint, heat_setpoint, or system_mode change on a dual-setpoint thermostat re-derives and re-pushes the displayed value. The climate zone is resolved automatically — the climate/HVAC/thermostat zone sharing the av zone's site space, preferring one that reports a temperature — or pinned explicitly with climate_zone_id in the remote's config (generating an RTI climate page writes its zone pick back to this setting). Driver 2.3.2 adds one boolean per system mode (climate_mode_heat, climate_mode_cool, climate_mode_auto, climate_mode_off), pushed as a complete set with exactly one true on every mode change, so a mode button can show its reversed state while that mode is active — reverse-state feedback binds a boolean, and a single mode string cannot light one of four buttons. A mode the driver has no variable for (dry, fan-only) leaves all four false. The manifest carries the current readings so a reconnecting remote starts correct.

AV updates (rti_source, volume, and friends) go only to remotes whose AV Zone setting names the changed zone. zone_state_N updates follow the remote's stored zone slot map instead — any zone a generated program put on one of the remote's subsystem pages reports its state there, whichever subsystem it belongs to. If the remote's config sets status_template, that template is filled in instead of JSON — and only for updates that carry one of its placeholder fields ([source], [multiview_source], [fullscreen]); the variables-format updates above are never sent to a template remote, so its line protocol sees no all-blank lines. Setting json_status to false suppresses updates entirely.

Discovery

If the controller's LAN address changes, every installed program still points at the old one — that used to mean regenerating and re-downloading each remote. From driver 2.3, a remote that cannot reach its configured address broadcasts a UDP probe (UDP port 6336 — same number as the bridge port, but UDP) after a few failed attempts; GEM answers with its current addresses and the remote follows, no re-download needed. The configured address is always tried first and wins again on the next driver restart, so discovery only ever acts on a connection that is already dead. Disable per remote with the driver's Enable Discovery setting, or controller-wide with remote_discovery: false in gem.json (remote_discovery_port changes the port).

Manifest

On connect, in reply to a hello, after a remote reload, and whenever an AV source or AV zone is edited, GEM sends JSON remotes a manifest — the full current picture instead of incremental updates:

{"type": "manifest", "manifest": {
"zonename": "Theater",
"generation": "3f9c2a81d04b",
"slots": [
{"slot": 1, "label": "Roku", "used": true},
{"slot": 2, "label": "Apple TV", "used": true}
],
"zones": [
{"slot": 1, "label": "Kitchen Cans", "used": true, "state": false}
],
"state": {"rti_source": 1, "volume": 25, "mute": false, "power": true, "sourcename": "Roku",
"nowplaying": "Bohemian Rhapsody", "artist": "Queen", "playing": true}
}}

The media keys (nowplaying, artist, playing) appear only when the zone carries media metadata, normalized exactly like the live updates above. volume and mute likewise appear only when the zone reports them.

The zones table appears only for remotes with a stored zone slot map; the driver (2.2+) applies it to its zone_state_N / zone_label_N / zone_used_N variables, with state true while the zone is on, open, unlocked, or armed. The GEM Automation RTI driver (2.1+) applies the slot table to its source_label_N / source_used_N variables — so renaming a source in GEM renames the button on the remote, and a source added into a spare slot appears, with no re-download. Slots come from the remote's stored slot map (written when a program is generated with the remote linked), falling back to the same derivation the highlight push uses. Remotes with a status_template never receive manifests.

Source Highlight Slots

Remote firmware cannot create indicators on the fly, so a remote driver declares a fixed set of source booleans and GEM reports which one is active as a slot number. The RTI driver declares twenty (rti_source_0 through rti_source_19).

Slot 0 means no source is active. GEM sends it when the zone is off, so binding it gives the zone an idle indicator. Sources occupy slots 1 and up.

Slots are assigned per remote, from that remote's own source key mappings, in the order the keys were added:

  • Slot numbers only need to be unique within a single remote, not across every source in the building. Two remotes can both use slot 1 for different sources.
  • Adding a source key later takes the next free slot and never renumbers keys already programmed into the remote's project file.
  • A source with no key mapping on that remote has no slot, and reports 0.
  • Past the driver's pool (slot 19 for RTI) a source reports 0 and GEM logs a warning naming the device.

To pin a source to a specific slot, set the rti_source attribute on the source device. An explicit value is site-wide and always wins over the assigned one — this is the shape systems commissioned before automatic assignment use, and those assignments keep resolving unchanged.

When a remote loads, GEM logs the slot each of its sources was given:

remote rti source slots: 4 theater 1=Roku 2=Apple TV 3=Blu-ray

Use that line when labelling the slots in the remote driver's own settings.


Troubleshooting

Remote Not Responding

  1. Verify the remote is powered on and connected to the network.
  2. Check that the IP address is correct.
  3. Ensure "Don't monitor connection" is unchecked if you want GEM to track connectivity.
  4. Verify the correct port is selected.
  5. Check that the remote is not in setup or pairing mode.

Key Not Working

  1. Verify the key is mapped in the key mappings grid.
  2. Check that the mapping is enabled.
  3. Confirm the action is configured correctly (device online, macro exists, source assigned).
  4. Check if the key is inherited from the master template and being overridden unintentionally.

Volume Not Working

  1. Verify an AV Zone is assigned to the remote.
  2. Check the volume step setting (1-5 range).
  3. Confirm the AV zone's volume device supports volume commands.
  • RTI - Generate Integration Designer projects from GEM configuration
  • AV Zones - AV zone configuration for remotes
  • AV Sources - Source configuration
  • Macros - Macros triggered from remote keys
  • Devices - Remote device configuration