Commands
Commands are individual control instructions within a command set. Each command has a name, a template string, and optional arguments that allow dynamic value substitution at runtime.
Overview
The Commands page manages the individual commands within a command set. It is accessed by clicking Edit on a command set row in the Command Sets page, or via the commands icon on a device row in the Devices page.
Viewing Commands
The main grid displays all commands in the selected command set:
- ID - Unique identifier
- Name - Command name (lowercase_with_underscores)
- Template - The command string or template
- Args - Defined argument names
- Source -
DRIVERfor driver-managed (system) commands,USERfor ones you added - Command Set - Parent command set
Header
- Title - Shows the command set name (or the device name, when the page is opened from a device's commands icon)
- Test Device selector - Choose a device for testing commands
- Reload button - Reload the selected test device
Grid Actions
- Add - Create a new command
- Edit - Open the command editor
- Delete - Remove a command
Quick Actions
- Test (remote icon) - Execute the command on the selected test device
Creating a Command
- Click Add in the grid toolbar
- Fill in the command details:
Command Fields
Name
- Internal identifier (lowercase_with_underscores)
- Auto-formatted on blur
- Examples:
power_on,set_volume,select_input
Template
- Raw command string sent to the device
- Use
[arg_name]for argument placeholders (e.g.,set_volume [level]) — each placeholder is replaced by the value of the argument with that name - When a command targets a zone, GEM auto-fills an
[address]placeholder with that zone's address (or, for a controller's child device, the device's address). So a template ofZONE[address] ONworks on its own — you don't have to declare anaddressargument or wire up anything - Don't type the
[@…]dynamic values directly into the template — they belong on an argument's options, not in the template string (see Dynamic Value Placeholders)
Arguments
Arguments define named parameters that are substituted into the template at runtime:
- Type an argument name in the Arguments list editor and press Enter
- The argument appears as a selectable item
- Click an argument to configure its options
Argument Options
When an argument is selected, you can define the allowed values:
- Add static values (e.g.,
on,off,toggle) - Add dynamic value placeholders that resolve at runtime using the buttons:
- Zone Address -
[@zone.address]- Resolved to the target zone's address - Device Address -
[@device.address]- Resolved to the device's address - Device ID -
[@device.id]- Resolved to the device's database ID - AV Zone -
[@av_zone.address]- Resolved to the AV zone's address - AV Source -
[@av_source.address]- Resolved to the AV source's address
- Zone Address -
When you add one of these placeholders to an argument's options, GEM expands it into a picker of the matching items — every zone, every device, or every AV zone/source — each labeled with its [id] and showing the address (or ID) it will send. Instead of typing a raw address or ID, you (or whoever later uses the command in the tester or a macro) choose the target from a dropdown, and that value fills the template's [arg_name] placeholder when the command runs.
Testing Commands
To test a command:
- Select a Test Device from the dropdown in the header (if you skip this, clicking Test just warns "Please select a test device")
- Click the Test icon (remote icon) on a command row
- If the command takes arguments — or its template contains a
[…]placeholder — a command tester opens:- Fill in (or pick) the argument values
- Click Test (the play-icon button) to send it
- If the command has no arguments and no placeholders, it executes immediately
- Results and responses appear as toast notifications
Device Console
When a test device is selected, a Device Console panel appears below the grid. It's a rolling log of the interaction with the device: commands sent from this page, their immediate replies, plus everything the device pushes back asynchronously — attribute changes and raw driver responses. This is where you verify a command actually did something ("I sent set_volume 30, the device echoed the new level") instead of trusting the toast. Clear empties the log; Hide collapses the panel.
Prompt Attributes
Some commands may trigger a prompt attribute response from the device, asking for additional input (e.g., a PIN code or confirmation). The console will display a dialog for the user to provide the value.
Command Templates
Templates define what is sent to the device. They support several placeholder syntaxes:
Static Templates
POWER ON
VOL UP
INPUT HDMI1
Argument Placeholders
VOLUME [level] → VOLUME 50
INPUT [input_name] → INPUT HDMI1
PWR [state] → PWR ON
Dynamic Value Placeholders
The [@…] placeholders ([@zone.address], [@device.address], [@device.id], [@av_zone.address], [@av_source.address]) are not typed into the template. They go into an argument's options — that is what the Dynamic Values buttons in the editor do. At edit time GEM expands the placeholder into a dropdown of the matching items so the value is picked, not typed; the picked value is then substituted into the template's matching [arg_name].
For example, to make a command pick which AV zone to address:
- Add an argument named
address - Select it, then click the AV Zone button to add
[@av_zone.address]to its options - Write the template as
SET [address] ON
When the command runs, the chosen AV zone's address replaces [address] — the device receives e.g. SET 3 ON. (For a command's own target zone you don't even need this — the auto-filled [address] placeholder described above already covers it.)
System Commands
Many device drivers ship with a built-in set of default commands. When a device connects for the first time (or after a GEM update adds new commands to a driver), GEM automatically syncs these system commands into the device's command set.
How System Commands Work
- Auto-created: When a device starts up, any commands defined by the driver that are missing from the command set are automatically inserted.
- System flag: System-managed commands have the
systemfield set totrueand show aDRIVERbadge in the Source column. - Driver is the source of truth: On every boot, GEM resyncs each field on the existing row from the driver definition.
template,args,arg_options, anddescriptionall follow the same fill-empty stop-gap rule: if the driver supplies a value, the driver wins; if the driver leaves the field empty, your local edit is preserved (see below). - Orphan cleanup: If a driver removes a command in an update, the corresponding system command is automatically deleted from the database. User-created commands (where
systemisfalse) are never removed by the sync process.
Editing Driver-Managed Commands
A command with the DRIVER badge is owned by the device's driver, which re-applies its definition every time the device boots. On this page that means most of the command is read-only:
- Name, Template, and Arguments are locked. When you open a DRIVER command in the editor those fields are greyed out, because the driver would rewrite them on the next boot anyway.
- Argument options are the one thing you can fill in — and only as a stop-gap, when the driver hasn't supplied options of its own. This is the escape hatch for patching a missing hint locally: for example, adding a
[@zone.address]option so a driver that shipped before the zone-picker convention still gets a labeled picker instead of a raw number field. If the driver already provides options for that command, the editor won't open it — you'll get a notice telling you to add a separate command instead. - Inline grid edits and deletion are blocked for DRIVER commands; both warn you, because a deleted system command is just re-created and an inline edit is reverted on the next boot.
Behind the scenes, anything the driver leaves unspecified is preserved across reboots, while any field the driver does define is restored to the driver's value — so the argument options you fill in survive until (and unless) the driver starts supplying its own.
If you need a permanent customization that conflicts with the driver, add a separate command with a different name. Custom commands (system = false) are preserved across updates and never overwritten by the sync process.
Identifying System Commands
In the commands grid, the Source column shows DRIVER for system-managed commands and USER for ones you've added. You can test driver-managed commands and use them in macros just like any other command. Deletion and inline edits are blocked, and any field the driver defines is restored on the next boot — the only thing you can fill in on this page is an argument's options, and only while the driver hasn't supplied them itself.
Command Name Aliases
GEM maintains an internal alias system for common command names. When a command is executed and the exact name is not found in the device's command set, GEM tries alternative names from the same alias group. For example:
fast_forward→ triesscan_forward,forward,ffrewind→ triesscan_back,reverse,scan_reverse,rwnext→ triesskip_forward,skip_nextvolume↔set_volumeinput↔set_inputpower_on→ trieson,discrete_onback↔returnselect→ triesok,enter
This means macros and automation commands work across different drivers even when naming conventions differ slightly.
Database Schema
| Column | Type | Description |
|---|---|---|
id | INTEGER | Primary key |
name | STRING | Command name (required) |
command_set_id | INTEGER | FK to parent command_set (required) |
template | TEXT | Command template string |
description | TEXT | Optional description (no length limit) |
args | JSON | Array of argument names |
arg_options | JSON | Object mapping argument names to arrays of allowed values |
system | BOOLEAN | Whether this command is managed by the driver (default: false) |
Import and Export
Exporting Commands
Use the grid Export button to save all commands to a file — CSV by default, or JSON via the checkbox in the export dialog (choose JSON if you plan to re-import the file; the Import button only accepts JSON). To export only specific commands, multi-select them first (click-and-drag or Ctrl+Click) — the same Export button then exports just the selected rows. Either way, GEM asks "Include IDs in export?": answer No when you intend to import the file into a different command set (so the rows come in as new commands rather than colliding with existing IDs).
Importing Commands
- Click the Import button in the grid toolbar
- Select a JSON file containing an array of command objects
- A confirmation dialog appears with the number of commands to import
- Replace existing commands — check this option to delete all existing commands in the set before importing. This is useful when loading a complete replacement command set rather than merging.
- Click OK to proceed
The replace option permanently deletes all existing commands in the command set before importing. Use this only when you want a full replacement, not a merge.
Best Practices
- Consistent Naming: Use descriptive command names matching the device protocol (e.g.,
power_on,volume_up) - Match the Protocol Exactly: The template is sent to the device as written, so copy the command's syntax, casing, and delimiters straight from the device's control protocol
- Test After Creating: Always test new commands with a real device before deploying
- Use Dynamic Values: Prefer
[@zone.address]over hardcoded addresses for reusable commands - Group Related Args: Keep argument option lists focused and ordered logically
Related Documentation
- Command Sets - Managing command set collections
- Devices - Device configuration and command set assignment