Skip to main content

Zones

Zones are the fundamental control units in GEM, representing controllable endpoints like individual lights, displays, thermostats, shades, or audio zones. Each zone is associated with a device and can have custom attributes for state management.

Overview

The Zones page provides comprehensive management of all control zones in your automation system, including configuration, attribute management, and programming impact analysis.

A single device commonly owns many zones — one hardware controller addresses each endpoint individually. For example, a Lutron processor drives every load and shade wired to it as its own zone:

Each zone carries its own Address (the channel, relay, or integration ID the device uses to reach that specific endpoint), so commands sent to a zone route through the shared device to the correct load.

Viewing Zones

The main grid displays all configured zones with the following columns:

  • ID - Unique identifier
  • Name - Internal zone name
  • Label - User-friendly display name
  • Subsystem - Logical grouping (lighting, AV, HVAC, etc.)
  • Device - Parent hardware device
  • Site Space - Room or area the zone belongs to
  • Address - Device-specific address (channel, relay, etc.)
  • Control - Zone control type
  • Enabled - Whether the zone is active
  • Sort Index - Display order in UIs

A zone also disappears from end-user UIs when the device it routes commands through is disabled. Four cases stay visible anyway, because they can still dispatch without that device: AV zones, zones with ONVIF camera attributes, zones carrying a command override (see Command Overrides), and zones with no device configured at all. Disabled zones and zones with a disabled device both remain visible in admin pages — see Devices.

Grid Actions

The toolbar above the grid offers:

  • Import - Bulk-create zones from a JSON file (the file picker accepts .json only)
  • Export - Download the zones currently shown. GEM asks two questions before the download: Include IDs in export? and Export as JSON instead of CSV — answer yes to the second when you plan to re-import the file
  • Add - Create a new zone
  • Refresh - Reload the grid data
  • Save Sort - Write the current visual row order into sort_index (appears because the grid includes that column)
  • Format - Tidy the Label of every visible row (or of the selected rows). It title-cases the existing label, falling back to the Name when the label is empty, so kitchen_island_pendant becomes Kitchen Island Pendant. Two-letter capitals are preserved (kitchen_TVKitchen TV)
  • Undo - Reverse the last cell edit (Ctrl+Z also works, and multiple steps are kept)

Hovering a row reveals its own toolbox: Move up / Move down, Reload, Edit and Delete. Reload re-binds that single zone on the running system — use it after changing a zone's device or address if you want the change applied without touching anything else.

If a grid fails to load or reload its rows, an error banner appears above it. The rows left on screen are the previous load's, so treat the banner as "this list is stale" rather than assuming the last action didn't apply.

Inline Zone Control

Each grid row with a configured Control type shows a gear icon in the toolbox column. Clicking it opens the zone's live control in a popup modal titled with the zone's label, letting you operate the zone without leaving the Zones page. The popup uses the same control component the zone renders in UIs (climate, dimmer, shade, lock, etc.), so changes are real-time and reflect actual device state. The active UI theme is applied inside the modal so buttons and themed controls render with their normal appearance.

If the zone references a user-defined Svelte widget by name in its Control field, the popup loads that widget instead. Rows with no control configured do not show the icon.

note

Some control values are rendered by a subsystem page rather than a standalone control — those are marked in the Zone Control Types table. Opening the popup for one of them reports no control component for "<control>". That is expected; the zone still works in the subsystem view and in UIs. The same message on a control you expect to render means the value is misspelled or names a widget that no longer exists.

Reference Cells

Cells that reference another entity (Subsystem, Device, Site Space — any column backed by an *_id field) show an open-in-new icon when hovered. Clicking it opens the referenced entity's editor in a modal, so you can inspect or edit the target without leaving the grid. The same button is available in the cell's edit mode. This applies to reference columns in every admin grid, not just Zones.

Multi-Select & Bulk Operations

The grid supports selecting multiple cells in a column for bulk editing and deleting:

  • Click a cell to select it
  • Ctrl+Click (Cmd+Click on Mac) to add or remove individual cells from the selection (must be in the same column)
  • Click and drag vertically to select a range of cells in a column
  • Escape to clear the selection (works regardless of where focus is)

Selection tracks row positions, so anything that changes which rows are on screen — sorting a column, applying or clearing a filter — clears it. This is deliberate: keeping it would silently re-point the selection at whichever records now occupy those positions, and since sorting also jumps back to page 1, a selection made further down the list would be acted on off-screen.

When more than one cell is selected, the toolbar swaps out its normal buttons for a selection summary (e.g. "3 cells in 2 rows") and its selection actions:

  • Set Attribute — Write one attribute across every selected row (see below)
  • Delete (trash icon) — Delete all selected rows (with confirmation)
  • Clear (close icon) — Deselect all cells

Bulk editing: Edit any selected cell and save — the new value is automatically applied to all other selected cells in the same column. Clearing a cell and saving writes a true empty value, so you can blank a field across the whole selection in one edit; Undo restores the prior value, including restoring a field back to empty.

Sequence fill: Include {i} in the typed value to number the selected cells in visual order instead of writing the same value everywhere — zone_{i} produces zone_1, zone_2, …; {i:4} starts counting at 4. Perfect for re-addressing a multi-channel device's zones ({i} in the address column gives 1, 2, 3, …) or renaming a batch in one edit. Every occurrence of the token in the value is replaced, and undo restores all prior values as usual.

Set Attribute: Bulk editing writes a column of the table; Set Attribute writes an attribute onto every selected row's entity — the same rows the Attributes page manages, one modal instead of opening each entity's Attributes tab in turn. Pick the attribute (the list comes from the Attribute Registry, filtered to the selection's driver when all rows share one; free-typed names are allowed), enter the value, and review the preview before applying: it lists exactly which entities will change with their current → new value, which will be created fresh, and which are skipped and why (read-only unless you tick the override, or already holding the value). After applying, the modal reads back what the server actually did per row. Writes go through the normal attribute path, so history, secure encryption, and attribute triggers all apply. The button appears only on grids whose rows are attribute-bearing entities (zones, devices, subsystems, UIs, macros, sites, …).

Exporting a subset

There is no "export selection" button — while a multi-cell selection is active the toolbar shows only the selection actions. To export part of the list, clear the selection, narrow the grid with the column filters, then press Export: it writes exactly the rows the filters left on screen.

Keyboard Navigation

Click any cell (or press an arrow key with the grid focused) to start navigating without the mouse. The focused cell is outlined; assistive technology follows it as the grid's active cell.

KeyAction
Arrow keysMove the focused cell. The first arrow key on a grid that has no focus yet enters at the top-left cell
Tab / Shift+TabMove to the next / previous cell, wrapping across rows
EnterEdit the focused cell
Home / EndJump to the first / last column of the row
Ctrl+Home / Ctrl+EndJump to the first / last cell of the whole list
EscapeClear the current multi-cell selection
Ctrl+ZUndo the last edit
Ctrl+CCopy the focused cell, or the whole selection when one is active

Navigation spans the entire filtered list, not just the visible page: arrowing past the last row of a page turns to the next page and keeps the focus, and Ctrl+End lands on the final row of the final page. Tab moves between cells only while the grid itself holds focus — tabbing from the toolbar, a column header, or the pager leaves the grid normally.

Copying Values

Cell text can't be selected with the mouse — a click-and-drag inside the grid is the range-select gesture described above, so it can't also be a text selection. Two ways to get a value out instead:

  • Ctrl+C copies the focused cell. With a multi-cell selection active it copies every selected value, one per line, in the order they appear on screen — click the top cell of a column, drag to the bottom, Ctrl+C, and paste the lot into a spreadsheet or a ticket.
  • Copy button — read-only cells show a small copy icon on hover. Editable cells don't need one: double-click gives you an input you can select from.

Masked fields (password columns) copy as their asterisks, never the stored value, and read-only true/false cells show a status dot with no copy button.

Dynamic Filters

Column filter dropdowns are context-aware — each column's filter options show only the values that exist in rows matching all other active filters. This makes it easier to narrow down results when multiple filters are applied.

Pagination

Grids paginate at 50 rows per page. When results exceed one page, a compact pager («/‹/›/» controls + page indicator) appears in the toolbar above the grid alongside the row count, and a full pager appears below the grid with First/Previous/Next/Last buttons and a "Showing X–Y of Z" counter. Sorting, filtering, and clearing filters reset to page 1.

Sorting a column stays applied while you work — editing cells, undoing an edit, running Format Labels, or refreshing the grid all preserve the sort order shown by the column header's caret.

Creating a Zone

There are two common workflows for creating zones:

From the Zones Page

  1. Click Add in the grid toolbar
  2. Fill in the General tab (see Zone Editor below)
  3. Click Create Zone
  4. Once saved, the Attributes and History tabs become available and the button changes to Update Zone

From a Device

The device editor's Zones tab embeds this full Zones surface — the same grid and editor — scoped to that device, so you can manage all of a device's zones without leaving it:

  1. Navigate to System > Devices
  2. Edit the device (save it first if it's new)
  3. Open the Zones tab and click Add — the new zone arrives with this device already selected and the Name pre-seeded with the device name, ready for you to extend (front_dimmerfront_dimmer_kitchen)
  4. Add, edit, sort, delete, or open live Zone Control for the device's zones in place
note

Zone Name must be unique across the entire system, not just within the device or subsystem. Names are lowercase letters, numbers, and underscores only — typing anything else reformats on the way out of the field.

From a Driver (auto-created zones)

Many drivers discover their own endpoints and create the matching zones themselves — WattBox outlets, SPAN circuits, matrix outputs, Meross sub-devices, VRF indoor units, eDIDIO fixtures, camera video sources, and more. You don't pre-create these: they appear on the first poll or connect, under the subsystem the driver picks, with Address set to the hardware's own identifier. Each driver's page under Drivers lists which subsystem and control it uses and whether a sync_zones command can force an immediate sweep.

Zone Name is unique system-wide, but the hardware labels those names are derived from are not — two amp outputs can both be called "Main Patio", and the name may already belong to a zone on another device (or to a row that isn't loaded, because its subsystem is disabled). Every driver resolves the name before inserting rather than letting the insert fail:

SituationWhat happens
The derived name is freeThe zone is created under it (usually <device>_<label>)
The name belongs to an unrelated zoneThe address is appended — <device>_<label>_3 — so the endpoint still gets its zone. The Label keeps the hardware's own name; only name is qualified. Drivers whose zone has no address (one zone per device) append the device id instead
The name belongs to this device's own zone at this addressThe existing row is left alone — never recreated, never driven. It's usually a zone whose subsystem is disabled; re-enable it and reload the device to pick it back up
Both the plain and the qualified name are takenThe create is skipped and logged (zone name unavailable, skipping create)

Only one create per address runs at a time, and an address whose create fails backs off for 10 minutes instead of retrying on every poll — a permanent collision can't duplicate zones or flood the log. Reloading the device clears the backoff and tries again immediately.

A zone you disable is remembered as well: discovery sees it and skips it, so disabling an outlet or channel you don't want is permanent rather than being undone by the next sweep.

Zone Editor

The zone editor provides four tabs: General, Attributes, Programming, and History. On a brand-new zone only General and Programming are shown; Attributes and History appear after the first save. (Opening Programming before saving reports "Please save the zone first".)

1. General Tab

Basic Information

  • Name (required) - Internal identifier, lowercase letters/numbers/underscores
  • Label (required) - Display name shown in UIs and mobile apps

Zone Configuration

  • Subsystem (required) - The subsystem this zone belongs to. Beyond organizing the list, the subsystem decides relay-state translation (see Relay State Mapping) and which subsystem page the zone appears on
  • Control - The UI control the zone renders as. The dropdown lists every built-in control value plus the name of every user-defined Svelte widget on the system, all in alphabetical order. See Zone Control Types

Device Assignment

  • Device - The hardware controller that carries this zone's commands. Optional: leave it blank and the zone falls back to the device assigned to its subsystem, which is how single-controller subsystems (one lighting processor for every light zone) are normally wired
  • Address - The control point on that device. The hint under the box is written by the selected device's driver and changes as soon as you pick a different device — it tells you exactly what this driver expects (a channel number, a relay id, a lock UUID, a Tesira instance tag, "Not used by this driver", …). See Addressing Zones

Zone Attributes — appears only when the selected device's driver declares zone-level settings, and is headed "· from (driver name)". Required settings render immediately; anything optional is collapsed behind a Show N optional attributes link. Optional settings still receive their declared defaults when you save, so leaving them collapsed never changes the resulting configuration. Editing an existing zone auto-expands the optional block if any of those values already differ from their default, so nothing configured stays hidden.

Space Assignment

  • Space - The physical room or area the zone lives in, picked from Site Spaces. Optional. Beyond scoping space-linked UIs, this is what places the zone on end-user floor plan maps — the pin is derived from the space's rectangle on the plan, with no per-zone placement work (see End-user floor plan maps)

Display Settings

  • Sort Index - Display order; lower numbers appear first
  • Status - The enabled switch. A disabled zone stays in admin lists but is withheld from end-user UIs
  • Elevated - Only elevated roles may send commands to this zone. Commands from anyone else are refused on every transport - the UI, the REST API, voice, remotes and macro steps

When to use Elevated on a zone rather than on the device

Devices have their own Elevated switch, and where every zone on a device is sensitive - a lock panel, an alarm panel - that remains the right place to set it.

The zone switch is for hardware that hosts zones of mixed sensitivity. An Axis intercom is a camera, a call button and a door strike on one device. A relay board drives landscape lighting on two outputs and a gate on the third. Marking the whole device elevated locks ordinary users out of the camera and the landscape lighting as well, so in practice the switch gets left off and the door goes unprotected.

Setting Elevated on the door or gate zone alone protects that output and leaves its siblings usable. The two switches are independent and either one refuses: a zone on an elevated device is still refused even with the zone switch off.

Elevation is about the physical surface, so a PIN session keeps it - a wall panel that a user PINs into can still operate an elevated zone, exactly as it can operate an elevated device. What a PIN session does not get is admin authority; see Roles.

Footer buttons (on a saved zone)

  • Duplicate - Prompts for a new name, then copies the zone and every one of its attributes to it. The Address is deliberately left blank on the copy, because the copy is a different physical endpoint — fill it in before you test. Use this for the second, third and fourth identical fixture instead of retyping the attribute list
  • History - Jumps to the Attribute History page scoped to this zone
  • Unified Activity - Opens Reports with a new Unified Activity report scoped to this zone
  • Back returns to the grid; Create Zone / Update Zone saves

Saved changes take effect immediately — the zone is re-bound to its device without restarting the server.

2. Attributes Tab

Zone attributes carry both live state written by the driver and configuration you set by hand. Add, edit and delete them here; see Attributes for how the editor works and what each value type means.

The attribute name picker is driven by a catalog, so the descriptions and value types below appear inline as you type. These are the attributes the core system reads and writes on a zone:

State

AttributeTypeMeaning
statestringThe zone's state — on, off, open, closed, and so on. This is the one charted by the History tab
levelintegerDimmer level, shade position, or fan speed
power_statestringon / off. On AV zones, polling amplifier drivers write the physical per-zone power here
powerfloatPower consumption in watts — not an on/off state
connectedboolWhether the endpoint is reachable
errorstringLast error message reported for the zone
battery / battery_levelintegerBattery level
smoke, co, gas, leak, panicboolSensor tripped flags

Climate

temperature, humidity, setpoint, heat_setpoint, cool_setpoint, deadband, mode, system_mode (heat/cool/auto/off), system_modes, fan_mode, fan_modes.

AV

volume, mute_state (on/off), input, input_device, input_device_id, source (the routed source device id), warm_up, volume_control (discrete, discrete_ramping or ramp — see Volume control mode), volume_ramp_speed, already_on, hidden_global_sources, multiview_source, multiview_fullscreen, stream_url, power_reconcile (default on) and power_reconcile_seconds (default 30).

min_volume / max_volume cap how loud the room can be driven from any volume slider — see Volume limits. Unlike min_level / max_level below, they restrict the slider rather than rescaling it: the number stays the real volume.

stream_url and image_url on a zone are camera URLs, which carry credentials. They are stored encrypted and are never sent to a client — see What the browser is told.

A camera zone also takes stream_mode (jpeg stills, the default, or video — the camera's own H.264 played by the browser), plus frame_rate, resolution, frame_quality and hardware_accelerator, which tune the JPEG path only. stream_audio carries the camera's microphone through in video mode; it is off unless set, and the tile stays muted until a viewer asks for sound. See Stream mode: stills or video, Audio and Stream Performance Attributes.

Media

track, artist, album, album_art, position, shuffle.

Entry — doors, gates and callboxes

AttributeTypeMeaning
camera_zone_idintegerCamera zone whose live feed renders alongside the zone's buttons. On a garage door it also groups that door under its own camera when the garage subsystem lists more than one — see Zone Controls
sip_addressstringIntercom or callbox at this entry, e.g. sip:front_door@192.168.1.50. Draws a Call button; empty means no button
hide_controlsboolHide the operate buttons and leave only the camera and the Call button. Presentation only — the verbs still work everywhere else. See Controls with their own settings

Level range

AttributeTypeMeaning
min_level / max_levelintegerThe part of the 0-100 range a dimmable load or a shade actually responds to. The Light (Dimmer), Shade (Position) and DMX RGBW controls scale their slider onto this window and send the real level — see Limiting a load's usable range. Optional; unset means no scaling

Relay and command behavior

AttributeTypeMeaning
relay_statesJSONCustom relay↔zone state map, overriding the subsystem default
normally_closedboolInvert the relay mapping for a normally-closed contact. Drivers that poll a raw digital point instead of a relay — Modbus, groov I/O — use the same flag to invert the reported state, which is also what an active-low input needs
<command>_actionJSONRun something else in place of a standard command — see Command Overrides
linked_zonesJSONArray of zone ids this zone fans every command out to — see Linked Zones
status_zoneint / JSONZone id whose state this zone mirrors, or an array of ids to aggregate across — see Linked Zones

Floor plan placement

AttributeTypeMeaning
space_positionJSONOptional override for where the zone's pin sits on a floor plan, as {"x": 25, "y": 80} — percentages of its site space's rectangle, so it survives the room being moved or resized and the plan being replaced. Leave it unset to have the position derived from the space, fanned out automatically when a room holds several zones of the same subsystem. See End-user floor plan maps
map_coordinatestringDeprecated and no longer read. Held a theme zone-map placement written by the old per-theme map editor. Existing values are inert; nothing needs cleaning up
note

Anything beyond this list comes from the driver, not from GEM itself — a Lutron zone carries color/hue/saturation, an eDIDIO fixture carries fixture_mode, a LoRaWAN zone carries dev_eui and payload_decoder, and so on. Those appear in the picker once the zone's device is set, and the ones the driver needs up front are already on the General tab under Zone Attributes. Consult the driver's own page under Admin Reference → Drivers for its list.

3. Programming Tab

The Programming tab provides powerful impact analysis, showing everywhere a zone is used in your system programming.

Search Programming

The search runs automatically the first time you open the tab. It examines:

  • Macros - Macro steps that control this zone (direct and indirect)
  • Triggers - Attribute triggers that act on this zone
  • UI Zones - User interfaces that display this zone
  • Widgets - Dashboard widgets showing this zone
  • Access Control - Rules that control this zone
  • Monitors - Monitors that reference this zone

A toast summarizes the tally, and the tab header keeps the running total:

Found 15 reference(s): 4 macro(s), 2 trigger(s), 6 UI(s), 2 widget(s), 1 access rule(s), 0 monitor(s)

Schedule Timeline

When macros that control this zone have enabled schedules, a Schedule Timeline section appears showing upcoming execution times. The timeline includes schedules for both direct macros and indirect parent macros. Each entry displays:

  • Schedule Name — The schedule's name
  • Macro Name — Which macro will run (indirect macros show a chain indicator, e.g., "parent_macro → child_macro")
  • Rule — The cron pattern or variable reference
  • Upcoming Occurrences — Next 5 execution times (for cron-based schedules)

The schedule and macro names are links — clicking one opens that schedule or macro in an editor modal right here, so the zone editor, its open tab, and the search results survive the detour.

Variable-based schedules (e.g., [$sunset]) are indicated with a "Variable-based schedule" badge since their exact times change daily. Schedules with no upcoming occurrences within their date range show "No upcoming occurrences".

This helps you understand when automation will affect the zone before making changes or deleting it.

Results Display

Each row shows an ID, a description, some context on the right, and up to two buttons:

  • View — For a macro or a trigger, this opens that item in an editor modal right here, so you keep your place; saving refreshes the reference list. For a widget, access rule, or monitor it navigates to that admin page, filtered to the single row in question. For a UI zone it opens the UI Zones Grid tab, scoped to the UI and subsystem that row belongs to
  • Remove — Detaches the zone from that reference (see Removing References)

Macro References:

Direct macro references show the macro name, step number, and step type. The bracketed number is the step's ID, and if the step includes a command it is displayed in a code badge:

[45] Macro: good_night - Step 3: command [off: zone_id=12]

Indirect macro references are parent macros that call a direct macro via a run_macro step. These are discovered recursively up to 5 levels deep and shown with a chain indicator:

[78] Macro: bedtime_routine → good_night - Step 1: run_macro
note

Indirect macro references do not have a Remove button since the zone is not directly referenced in those macros.

Trigger References:

Trigger references indicate whether the zone is used in the trigger's Action, Condition, or both:

[12] motion_lights_on - Action - Enabled: Yes
[15] occupancy_check - Condition - Enabled: Yes
[18] combo_trigger - Action & Condition - Enabled: Yes

UI Zone References:

[88] UI: kitchen_panel - Kitchen Panel - Enabled: Yes

The UI name is a link that opens that UI's editor in a modal; the View button navigates to the UI Zones page, opening the Grid tab on the slice of assignments this row lives in — filter the ID column there to isolate the row itself.

Widget References:

[23] living_room_lights - light_control - Title: Living Room

Access Control References:

[5] front_door_unlock - unlock - Enabled: Yes

Monitor References:

[7] display_power_monitor - Power Zone - Enabled: Yes

Removing References

Click the Remove button next to any reference to remove the zone from that programming element:

  • Macros: Removes the zone from the step, leaving the step in place
  • Triggers: Removes the zone from the trigger's action (not offered for condition-only references)
  • UI Zones: Deletes the UI zone binding
  • Widgets: Removes the zone from the widget configuration
  • Access Control: Removes the zone from the rule's control configuration
  • Monitors: Clears the monitor's power zone

Important: Removing a zone from programming does NOT delete the programming element itself, it only removes the zone reference. For example, removing a zone from a macro step leaves the step intact but without a target zone.

4. History Tab

Charts the zone's state attribute over time, using the same controls as the Attribute History page. The System Target and Target Object are preset to this zone — pick any history-enabled attribute and a date range to view the chart.

Useful for reviewing how a zone's level, power, or other state has changed, diagnosing unexpected behavior, or correlating zone activity with automation events.

For the broader picture, the Unified Activity button in the zone editor footer (next to History) opens Reports with a new Unified Activity report pre-scoped to this zone.

Zone Control Types

The Control value decides what the homeowner sees and touches. It does not decide what commands the zone accepts — that comes from the device's driver. Pick the control that matches the hardware's real capability: a light_dimmer on a switched (non-dimming) relay gives the homeowner a slider that does nothing.

Type into the Control box to filter the list. These are the built-in values:

ControlShown asTypical subsystem
climate_defaultClimateclimate
climate_dual_setpointClimate (Dual Setpoint)climate
climate_locked_deadbandClimate (Locked Deadband)climate
climate_readonlyClimate (Read-Only)climate
climate_setpointClimate (Setpoint)climate
climate_simpleClimate (Simple)climate
contact_defaultContact Sensorsecurity
dmx_rgbwDMX RGBWlights
door_lockDoor Locksecurity, access
fan_defaultFan (Speed)fan
fan_onoffFan (On/Off)fan
fireplace_defaultFireplacefireplace
gate_defaultGategates
gate_open_close_stopGate (Open/Close/Stop)gates
high_medium_low_offHigh/Medium/Low/Offfan
leak_defaultLeak Sensorsecurity
lift_advancedLift (Advanced)lifts
lift_defaultLiftlifts
light_colorsLight (Colors)lights
light_dimmerLight (Dimmer)lights
light_momentaryLight (Momentary)lights
light_spectrumLight (Spectrum)lights
light_switchLight (Switch)lights
open_close_stopOpen/Close/Stopgates, shades
power_defaultPowerpower
power_switchPower Switchpower
sauna_defaultSaunasauna
sensor_defaultSensorclimate, security
shade_dimmerShade (Position)shades
shade_manualShade (Manual)shades
shade_switchShade (Switch)shades
single_buttonSingle Buttonany
smoke_defaultSmoke Alarmsecurity
spa_defaultSpaspa
switch_bankSwitch Bankany
thermostat_defaultThermostatclimate
tv_arm_defaultTV Armav
two_buttonTwo Buttonany
water_onoffWater (On/Off)water
water_onoff_setpointWater (On/Off + Setpoint)water
water_setpointWater (Setpoint)water
water_temperatureWater Temperaturewater
zone_combinerZone Combinerany

Ten of these have no standalone control and are drawn by their subsystem page instead — contact_default, leak_default, smoke_default, sensor_default, thermostat_default, power_switch, sauna_default, spa_default, light_momentary and shade_switch. They are valid choices; they just don't open in the grid's control popup.

Any Svelte widget you build also appears in this list by name — pick it to give a zone a bespoke control. See Widgets.

Picking a water control

Four controls cover the water/pool subsystem, and the difference is only which parts of the tile you get:

ControlWater temperatureSetpoint arrowsOn/off buttons
water_temperatureyes
water_setpointyesyes
water_onoffyes
water_onoff_setpointyesyesyes

Reach for water_setpoint when the heat setpoint is GEM's to set but the power is not: a boiler or heat pump on its own aquastat, or a pool heater slaved to the pump circuit, where an on/off pair would either no-op or fight the equipment. Use water_onoff_setpoint when GEM genuinely owns the on/off state — the Pentair ScreenLogic body circuits are the reference case.

The setpoint arrows only act on values that read between 50 and 140, which matches °F. On a °C-configured controller the temperature and setpoint display correctly but the arrows will refuse — use the driver's own setpoint command until the control is unit-aware.

Controls with their own settings

Eight controls read extra zone attributes:

dmx_rgbw — 4-channel DMX RGBW fixtures (also drives eDIDIO fixtures).

  • fixture_modedimmer, rgb, rgbw or dali; defaults to rgbw. The white slider only renders in rgbw mode; the other modes show level and color only
  • default_white — the white level (0-255) used when the fixture is switched on

door_lock, gate_default, gate_open_close_stop and open_close_stop — entry points, each drawing its operate buttons plus an optional camera feed and intercom button.

  • sip_address — SIP address of the intercom or callbox at the entry (e.g. sip:front_door@192.168.1.50). Draws a Call button. Leave empty and no button appears
  • camera_zone_id — camera zone whose live feed renders alongside the buttons
  • hide_controls — set true to drop the operate buttons (Lock/Unlock on a door, Open/Close/Stop/Hold Open on a gate), leaving just the camera and the Call button. This is the intercom-only entry: a lobby callbox, a driveway gate on the neighbour's opener, or a door whose strike belongs to someone else's access system — something GEM answers but must never release
  • Set sip_address or camera_zone_id alongside hide_controls. With neither there is nothing left to draw, and the tile says which attribute is missing rather than rendering blank
  • gate_default also has hide_close and hide_hold_open for trimming a single button; hide_controls is the all-of-them case
warning

hide_controls is presentation only, not an access restriction. The lock / unlock / open / close verbs are untouched — macros, triggers, voice, the REST API and any other UI still operate the zone. To actually prevent a door being unlocked, restrict it with Roles or don't give the zone a lock command in the first place.

switch_bank — one on/off switch per zone, stacked into a single control.

  • zone_id — the zones to include, as a single id, an array ([12, 13]), a JSON string, or a comma list (12, 13). With nothing set, the bank shows just the host zone
  • Each row is a standard light switch that reflects and toggles its own zone's state — on / off go to the listed zone, not the host
  • Ids that don't resolve to a zone are skipped; if none resolve, the control shows a hint to set zone_id
  • Use for presenting several related on/off zones as one control (e.g. a DMX Switch star ceiling with a separate twinkle-effect channel, or a relay bank)

zone_combiner — stacks each listed zone's own configured control instead of a uniform switch row.

  • zone_ids — the zones to stack

water_onoff — the two-button valve tile, for shutoffs whose vocabulary isn't "on" and "off".

  • on_text / off_text — the words on the two buttons; default On and Off. A water shutoff usually wants Open / Close
  • on_state / off_state — the state values that light each button up; default on and off. Set them to whatever the driver actually publishes (open / closed) so the tile highlights the position the valve is really in
  • The commands sent are always on and off — these four attributes are presentation only, so a driver needs to know nothing about them
  • Moen Flo seeds all four when it auto-creates a shutoff zone; relabelling them afterwards sticks

Limiting a load's usable range

Some loads only respond across part of the 0-100 range. A DMX channel wired to a mains dimmer might do nothing visible below 51 and nothing more above 70; a shade might have travel limits well inside its nominal span. Left alone, most of the slider does nothing and the useful part is a sliver.

Two optional zone attributes fix the presentation:

AttributeTypeMeaning
min_levelintegerThe lowest level the load actually responds to
max_levelintegerThe highest level that still changes anything

Set them and the slider still runs 0-100, but maps that span onto the usable window and sends the real level:

  • Slider 100 sends max_level, slider 1 sends min_level, and everything between is linear
  • Slider 0 always sends 0 — off stays off, and a shade still closes fully. 0 is a state the load always accepts, not a point on the dimming curve, so it is never scaled
  • A level above 0 never displays as 0, so a lit load can't read as off

Honored by the Light (Dimmer), Shade (Position) and DMX RGBW controls. On DMX RGBW it applies to the level slider only — the white channel is a raw 0-255 DMX value and is passed straight through.

Both attributes are optional, and each works without the other (max_level alone caps the top; min_level alone lifts the bottom). Leave them unset — or set 0 and 100 — and the slider passes levels through untouched, exactly as it did before. A pair that is inverted, non-numeric or outside 0-100 is ignored rather than obeyed, so a mistyped value can't leave a load unreachable.

note

This is presentation only. The level stored on the zone, charted in history, and sent by macros, triggers, drivers and the API is always the real one — a macro that sets the zone to 60 still sets 60, and a driver needs to know nothing about the window. Widening it later leaves every previously stored level meaning exactly what it meant. Group and scene levels, which are sent to many zones at once rather than through one zone's control, are also unscaled.

Addressing Zones

The Address field maps the zone to a specific control point on the device. The correct format is always whatever the selected device's driver says in the hint under the field — read it before typing. Some drivers don't use the address at all ("Not used — main zone only"), in which case leave it blank.

Common shapes you'll meet:

Channel or output numbers

Most multi-channel dimmers, amplifiers and matrices use a plain 1-based number:

1, 2, 3, 4, ...

Module and port

Relay and IR controllers commonly address module:port or module.relay:

1:1, 1:2, 1:3 (iTach IR/relay modules)
1.1, 1.2, 2.1 (module.relay)

DMX start channel

DMX fixtures use the starting channel number. The driver maps the consecutive channels from there:

1 (RGBW fixture occupies channels 1, 2, 3, 4)
10 (RGBW fixture occupies channels 10, 11, 12, 13)

Valid DMX start addresses run 1 to 509 for a 4-channel RGBW fixture.

Cloud and integration identifiers

Cloud-connected products address by the identifier their own service assigns. These are usually enumerated for you — run the driver's discovery/list command from the device's Commands tab and copy the value:

ABCDEF1234567890ABCDEF1234567890 (August lock ID)
2960123456 (Airthings serial number)
front_porch (Frigate camera name, case-sensitive)
L7.400 (CoolMaster unit UID, Line.Address)
ConfRoomLevel:3 (Biamp Tesira instance tag + channel)
083203000100 (HiQnet object address)

Consult the driver's page under Admin Reference → Drivers for the exact addressing rules.

Relay State Mapping

When a zone is driven by a dry-contact relay, "relay closed" does not mean the same thing for a gate as it does for a light. GEM translates automatically, in both directions, based on the zone's subsystem.

Default mappings

SubsystemRelay closed meansRelay open means
gates, garages, lifts, shadesopenclosed
doors, locksunlockedlocked
lights, fans, fire, power, wateronoff
securityarmeddisarmed

So a shade wired to a relay reports open when the contact is closed, exactly like a gate — not "closed".

Custom mapping

Override the default with a relay_states attribute (JSON) on the zone. The map is keyed by the relay state, and each value is the zone state it produces:

{
"closed": "on",
"open": "off"
}

A relay_states attribute on the zone wins over one on the subsystem, which wins over the built-in defaults above.

For the common case of a normally-closed contact, you don't need the JSON at all — set normally_closed to true on the zone and GEM flips whichever mapping applies. The default assumes a normally-open relay (relay closed → gate open, relay open → gate closed); normally_closed=true gives you relay closed → gate closed, relay open → gate open.

warning

A zone whose subsystem isn't in the table above — a custom subsystem name — has no mapping, and the raw relay state (open / closed) reaches the UI untranslated. Give the zone (or the subsystem) an explicit relay_states attribute in that case.

Command Overrides

For exotic hardware that doesn't respond to a subsystem's standard command (e.g. a shade wired to a relay that needs a momentary pulse instead of an open), add an attribute named after the command with _action appended, holding JSON. When present, the override is dispatched instead of the normal command.

The rule is general: <command>_action overrides <command>. open_action replaces open, close_action replaces close, stop_action replaces stop, on_action replaces on, off_action replaces off, lock_action replaces lock, and so on for any command the zone would otherwise receive.

The value can run a command on any device:

{
"command": "pulse",
"device_id": 7,
"args": {"address": "1:4", "delay": 500}
}

Or run a macro:

{
"macro_id": 42,
"args": {}
}

Any caller of the original command — UI buttons, macros, triggers, the AI assistant — flows through the override automatically. Only the matching command is replaced; everything else on the zone behaves normally. Overrides don't recurse: the command inside the override runs as written, even if it names the same verb.

An override is a capability grant

The override runs exactly as stored, without re-checking the caller's authority against the new target — writing zone attributes requires an elevated session, so the stored target is the integrator's deliberate choice, and an inline address in its args is trusted the same way. Attaching an override that operates an elevated device, or runs an elevated macro, therefore grants that action to every user who can send the overridden command to this zone. That is usually the point — a shade verb that pulses a gate relay — but make it a decision: the attribute editor shows a warning when a saved <verb>_action operates an elevated target. See Elevated devices and macros.

A zone that carries an override also stays visible in end-user UIs when its own device is disabled, because the override gives it another route.

Use sparingly

Prefer the right driver and a correct relay-state mapping when possible. Reach for <command>_action only when the hardware genuinely requires a different command shape than the subsystem's defaults.

Linked Zones (operate a group as one)

When several physical outputs should behave as a single zone — three fountains on separate Lutron addresses that the client thinks of as "the fountains" — two attributes turn one zone into the face of the group:

AttributeDirectionMeaning
linked_zonescontrolJSON array of member zone ids, e.g. [12, 13, 14]. Every command sent to this zone is re-dispatched to each member as if it had been commanded directly — including the member's own relay mapping and <command>_action overrides. Caller-supplied args (level, fade_rate, …) carry through
status_zonestatusWith an array value naming the same members (e.g. [12, 13, 14]), this zone's state aggregates from the group: sources that all agree mirror that state; a mixed set reads as the first member whose state is active (anything other than off / closed / stopped / idle). Any member on shows on; only all-off shows off. The original scalar form — a single zone id whose state is mirrored 1→1 — is unchanged

Recipe — three fountain zones with ids 12, 13, 14:

  1. Create a fourth zone "Fountains" on the same subsystem, with no address.
  2. Add attribute linked_zones (json) = [12, 13, 14].
  3. Add attribute status_zone (string or json) = [12, 13, 14].
  4. Show only the master in end-user UIs; keep the members for service.

The master now controls all three, and its tile reads on whenever any of them runs — including when one is started from a Lutron keypad GEM didn't see the command for.

Leader pattern: if the master zone has its own address (say fountain 1 is the master and linked_zones = [13, 14]), it joins the fan-out as the first member, so its own output is driven too.

Notes:

  • A member that is itself a linked master expands in turn — a group of groups works. Cycles are detected and cut rather than recursing.
  • Elevation is not bypassed: commanding the master checks the caller's authority against every member (and every member of a nested master), exactly as if the members had been addressed directly. A non-elevated user cannot reach an elevated zone by commanding its master. This is deliberately the opposite of a <command>_action override, where the admin fixed the command and the target — here the caller picks the verb, so each member is judged.
  • A verb the master overrides with <command>_action runs the override instead of fanning out — the override remains the more specific escape hatch.
  • For audio/video zones, use the existing AV group mechanism (av_group) rather than linked_zones.
  • Only state aggregates. Member level values are not combined onto the master.

For grouping zones visually without a master zone, see UI zone groups — a command sent to [@group_name] fans out to the group's members without any linking attributes.

Best Practices

  1. Naming: names must be unique system-wide, so build them from room + load:

    living_room_main_lights
    kitchen_island_pendant
    master_bedroom_ceiling_fan
  2. Labels: the homeowner only ever sees the label — keep it short and room-relative:

    Main Lights
    Island Pendant
    Ceiling Fan

    The Format toolbar button generates labels from names in bulk if you named things well.

  3. Subsystem: pick it deliberately — it drives relay translation and subsystem-page placement, not just grouping.

  4. Space: set the Space on every zone. A UI bound to a site space pulls in that space's zones automatically (and its child spaces when the UI says to), room-level voice questions — "which rooms have shades?", "turn off the lights in here" — are answered from this field, and end-user floor plan maps place their pins from it.

  5. Sort Index: order zones the way the homeowner walks the room — drag the rows, then press Save Sort.

  6. Enabled: disable rather than delete during commissioning, troubleshooting, or when equipment is temporarily out.

  7. Repeat fixtures: for the second and third identical load, use Duplicate (it copies every attribute) and then set the new Address — much faster and less error-prone than retyping.

  8. Programming review: before deleting a zone, open the Programming tab, note the Schedule Timeline, and clear the references.

  9. Test before wiring up: prove the zone with the grid's control popup before adding it to a UI or a macro.

  10. Address validation: verify the address against the physical device configuration — a zone that "does nothing" is usually a zone addressed to a channel that isn't there.

Common Workflows

Adding Multiple Zones for a Device

When adding a multi-zone device (like an 8-channel dimmer):

  1. Create the device first
  2. Open its Zones tab and add the first zone — device and name are pre-filled
  3. Set the address to channel 1, choose the subsystem and control, save
  4. Duplicate it seven times, then multi-select the Address column and type {i} to number the channels 1-8 in one edit

Or use Import to bulk-create the zones from a JSON file.

Replacing a Device

When replacing hardware:

  1. Multi-select the Device column across the affected zones and bulk-edit it to the new device
  2. Update the addresses if the new hardware numbers its outputs differently
  3. Test each zone from the grid's control popup
  4. Disable or delete the old device

Reorganizing Zones

To change zone order in UIs:

  1. Drag zones into the desired order
  2. Click Save Sort in the grid toolbar
  3. Confirm the prompt — sort_index is renumbered across all rows currently in view

Advanced Topics

Zones without their own device

The Device field is optional. A zone with no device falls back to the device assigned to its subsystem — the normal arrangement when one processor drives an entire subsystem. A zone with no device anywhere still lives in UIs and macros and still holds attributes; it just has nothing to send commands to, which is exactly what you want for a zone that only ever displays a computed or externally-written value.

Zones that combine other zones

Rather than pointing several zones at the same load, model the group explicitly:

  • switch_bank for a stack of on/off zones in one control
  • zone_combiner for a stack of each zone's own control
  • A macro for anything that needs ordering, delays, or conditions

Watching a zone over time

Enable history on the attributes you care about and use the History tab. For state that must not diverge between two controls of the same load, add an attribute trigger that compares the two and corrects one — see Triggers.

Troubleshooting

Zone Not Responding

  1. Check Enabled: verify both the zone's Status switch and the device's enabled state
  2. Verify Address: confirm the address matches what the driver's hint asks for
  3. Test the device directly: run the command from the device editor's Commands tab — if it fails there, the problem is the device, not the zone
  4. Check for an override: a stale <command>_action attribute silently redirects the command somewhere else
  5. Review Logs: check for communication errors on the device

State Not Updating

  1. Check Driver Feedback: verify the driver parses device feedback (see device logging)
  2. Enable Logging: view raw device feedback
  3. Test Polling: verify device polling is working
  4. Review Triggers: check for a trigger writing the attribute back

Relay Reads Backwards

A gate that reports "closed" when it is open, or a light that shows on when it is off, is a relay mapping problem, not a driver bug. Set normally_closed on the zone; if the subsystem is a custom one with no default mapping, give the zone an explicit relay_states map instead.

Control Popup Says "no control component"

The zone's Control value doesn't match a built-in control or an existing Svelte widget. Re-pick it from the dropdown. If the value is one of the ten subsystem-drawn controls listed above, this is expected — view the zone from its subsystem page instead.

Auto-Created Zone Is Missing or Has an Odd Name

A zone the driver created with the address appended to its name (..._3) means another zone already held the plain name — expected, and harmless: rename the Label freely, only name has to stay unique. A discovered endpoint with no zone at all usually means the name is taken by a row you can't see: check the device log for zone row exists but is not loaded (re-enable that zone or its subsystem) or zone name unavailable, skipping create (rename the zone holding the name, then reload the device). See From a Driver.

Zone Missing from a UI

Check, in order: the zone's Status switch, whether its device is disabled, and whether the zone is actually bound to that UI in UI Zones.