Skip to main content

UIs

UIs (User Interfaces) represent distinct dashboard instances that can be accessed via web browsers, tablets, or mobile devices. Each UI can have unique zones, controls, themes, and pages tailored to specific users or locations.

Overview

GEM supports multiple UIs, allowing you to create:

  • Room-specific control panels (kitchen, living room, bedroom)
  • Role-specific dashboards (homeowner, guest, installer)
  • Device-specific interfaces (wall-mounted tablets, mobile phones)
  • Location-specific controls (main house, guest house, pool area)

Viewing UIs

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

  • ID - Unique UI identifier
  • Name - Internal UI name
  • Label - Display name
  • Group - UI grouping category
  • Site Space - Linked Site Space; when set, the UI is space-linked and its zones come from zone.site_space_id
  • Show Child Spaces - When Site Space is set, include zones from descendant spaces too (read-only when no space is linked)
  • Sort Index - Display order
  • Enabled - Whether the UI is active

System UI (ID 0) represents the default UI.

Grid Actions

  • Add - Create a new UI
  • Edit - Modify an existing UI
  • Delete - Remove a UI
  • Sort - Reorder UIs by dragging rows
  • Reload - Refresh the grid data

Quick Actions (Toolbox)

For each UI row:

  • Logout Icon - Force logout all sessions on this UI (prompts for confirmation)
  • Notification Icon - Test web push notifications for this UI
  • View Icon - Open the UI in a new browser tab

Header Actions

  • Reload All - Force reload of all active UIs (prompts for confirmation, refreshes every connected client)

Toolbar Actions

The grid toolbar includes the standard DataGrid actions plus:

  • Format Labels (label icon) - Normalize the label column via formatLabel (treats any non-alphanumeric as a word break and capitalizes the first letter of each word). Short all-caps words of 2 letters or less are kept as acronyms (kitchen_TVKitchen TV, master_BRMaster BR), but longer all-caps words are Title Cased to tame shouting (KITCHENKitchen, MAIN_LOFTMain Loft). Mixed-case words preserve their inner casing. Scope follows the current view: with rows multi-selected only those rows are formatted, otherwise every row matching the current filters (across all pages). Shows a confirmation with the count of labels that would change, skips ones already in canonical form, and the change is undoable. Available on any DataGrid backed by a model with a label column.
  • Undo (undo icon, also Ctrl+Z) - Reverts the most recent grid edit. Covers single-cell edits, bulk fan-outs across a multi-cell selection, drag-reorder sort_index changes, and Format Labels runs. Stack is bounded at 20 steps and lasts only as long as the grid is mounted.

Creating a UI

To create a new UI:

  1. Click Add in the grid toolbar
  2. The UI editor opens with two tabs: UIs and Attributes
  3. Configure the UI properties (see sections below)
  4. Click Save

UI Editor

UIs Tab

Configure the basic UI properties:

Basic Information:

  • Name - Internal identifier (lowercase_with_underscores)
  • Label - Display name shown in UI selector
  • Group - Optional grouping category
  • Enabled - Toggle UI active state
  • Sort Index - Display order in UI selectors

Examples:

Name: kitchen_panel
Label: Kitchen Panel
Group: main_floor
Enabled: Yes

Attributes Tab

UI-specific attributes control behavior and appearance:

Common UI Attributes:

Theme:

  • theme - Theme name (set via UI Themes page)
  • Controls all visual styling

Gallery:

  • gallery_photo_path - Path to gallery images folder
  • Used for screensaver/photo frame mode
  • Example: /mnt/photos/family

Screensaver:

  • screen_timeout - Idle time before screensaver (seconds)
  • screen_timeout_action - What to do on timeout:
    • not_set - No action
    • gallery - Show photo gallery/screensaver
    • logout - Log out user
    • goto_page - Navigate to specific page

Navigation:

  • default_page - Page to show on login
  • home_button_action - What home button does
  • back_button_enabled - Show/hide back button

Layout:

  • zones_per_row - Number of zones per row in grid layouts
  • compact_mode - Reduced spacing for smaller screens
  • show_labels - Show/hide zone labels

Sorting:

  • ui_group_sort - How zone groups are sorted in control pages. Set to alphabetical to sort groups by name instead of the default sort index order.

Notifications:

  • web_push_enabled - Enable browser push notifications
  • notification_sound - Alert sound file

Camera Streaming:

  • rtsp_release_ms - Grace window in milliseconds before the client RTSP socket pool tears down an idle camera connection. Default 5000. Higher values keep streams warm across UI transitions (e.g. opening/closing a zone modal) at the cost of holding sockets open after navigation; lower values release server-side ffmpeg decoders sooner but may re-handshake on quick re-opens.

Lutron Keypad Widget Binding:

  • lutron_control_station_id - Station id consumed by the Lutron Keypad widget when its Use UI attribute option is on. Lets one widget definition follow whichever UI it's rendered under instead of hard-coding a station per UI page. Populated automatically by the lutron_qsx device's sync_areas command for any UI whose site_space_id matches a Lutron area that has control stations. When edited manually, the attribute editor shows a station picker (with area name) sourced live from the lutron_qsx driver instead of a free-text id field.
  • lutron_control_station_2_id, lutron_control_station_3_id, ... - Additional stations from the same area, written when an area has more than one keypad. Stations are sorted by name (then station id) so re-syncs land the same physical keypad in the same slot.

:::tip Live keypad state without a full sync On every connect, the lutron_qsx driver walks the processor's areas and subscribes to every LED (/led/{href}/status) and every keypad device (/device/{id}/button/status/event — one subscribe per device covers all of its buttons via LEAP's MultipleButtonStatusEvent). LED and button state goes live as soon as the device connects, without running sync_areas or syncZones first, and new keypads are picked up automatically after a project republish. The led_subscriptions (LED hrefs) and button_subscriptions (keypad device ids) attributes are persisted so the next reconnect's fast path can restore subscribes without re-discovering, and remain available as optional override lists for installs that need explicit subscribes. :::

AI Chat (Ask GEM):

  • hide_ai_chat - Hide the Ask GEM button from this UI's top nav. Default off (button shown).
  • The button only appears when an Anthropic API key is configured server-side (ai.anthropic_api_key in gem.json or the anthropic_api_key system attribute). Tapping it opens an in-page chat that lets users control the home in plain English (lights, climate, shades, AV, scenes), with optional spoken responses on devices that support the Web Speech API.

:::tip Room-name resolution When a user asks for something like "turn off the kitchen lights" or "dim the master bedroom to 30%", Ask GEM resolves the room phrase by matching it against the name, label, and group of every UI first. If a UI matches and is space-linked, its Site Space (plus descendants when include_child_spaces is on) defines the scope; if it's a manual UI, the scope is its UI Zone list. If no UI matches, the assistant falls back to a substring match on zone label/name. Naming a UI after the room it controls (kitchen, master_bedroom, downstairs) gives the assistant a much sharper sense of "where" — without it, ambiguous phrases like "downstairs" depend on every relevant zone happening to contain that word. :::

:::tip Delayed commands and cancellation Ask GEM understands deferred actions ("turn off the patio lights in 30 minutes", "in an hour set the kitchen lights to 20%", "lock the front door in 5 minutes") and queues them in-memory, capped at 8 hours per timer and 20 zones per fan-out. Users can also cancel pending timers ("cancel that timer", "never mind", "cancel the patio timer", "cancel all my timers") or list what's pending ("what timers do I have set?"). Timers are sandboxed per user — one user's pending timers can't be seen or cancelled by another. Pending timers do not survive a server restart; for recurring/persistent rules use Macro Schedules instead. :::

:::tip "Lock up" / "secure the house" Ask GEM can lock every accessible door and arm the alarm in one breath ("lock up", "secure the house", "I'm leaving — lock up", "going to bed, lock up"). Defaults to stay mode for "lock up" / "going to bed" phrasings; use "I'm leaving" / "arm the alarm" for away mode, or "just lock the doors" to skip arming. The sweep is hard-scoped to door/lock/gate and security zones the user can already see on this UI, capped at 30 of each, and skips zones already locked or armed (so re-asking is a no-op). Garage zones are included by default — say "just the interior locks" to exclude them. Unlocking and disarming are intentionally not voice-controllable — for safety, the assistant will direct the user to the touchscreen instead. If you have a curated goodnight / lock_up / leave_home macro on the UI, the assistant prefers running that over the generic sweep so any associated lights/scenes fire too. :::

See UI Themes and Gallery for theme and gallery configuration.

Accessing UIs

Direct URL Access

Access a specific UI by URL parameter:

https://gem.local/?ui_id=1
https://gem.local/?ui_id=5

Or by UI name:

https://gem.local/?ui=kitchen_panel
https://gem.local/?ui=master_bedroom

UI Selector

When multiple UIs exist, a UI selector appears allowing users to switch between UIs. The selector is a single tile grid that drills down into Site Spaces, UI groups, or a flat All view, with a breadcrumb back button at the top of any sub-view.

Root tiles mix three sources, sorted together by sort_index (alpha tiebreak; set ui_sort: alphabetical in app settings to sort by label only):

  • Top-level site spaces — each space with a linked UI lands you in it on tap, and spaces with child spaces show a suffix so you can drill in. Spaces with both a UI and descendants act as both — tap navigates, hold-to-set-default still works.
  • UI groups — every distinct group value from non-space-linked UIs becomes a drill-down tile (suffixed with ). Group order honors settings.ui_groups if set, otherwise falls back to the smallest member sort_index.
  • Ungrouped manual UIs — UIs with no site_space_id and no group show as direct tiles at root.
  • All — a flat list of every UI, always pinned at the top of root when any UIs exist.

Drill-down pushes onto a stack so the back button (‹ Home / ‹ Parent Name) pops one level at a time. Searching collapses the view to a flat filtered list across every UI regardless of current scope; clearing the search restores the drilled scope.

Hold any UI tile for 2 seconds to set it as the default UI for that device (same behavior as before — stored against gem_client_id + user agent).

The selector toolbar also exposes per-device actions that don't require admin access:

  • Clean Screen — temporarily disables touch input so the screen can be wiped down
  • Request Notifications — prompts the browser for web push permission
  • Show / Hide Media Nav — toggles the media navigation bar
  • Zoom — opens a modal that scales the entire UI between 50% and 150% via document.documentElement.style.zoom. The chosen value persists in localStorage (gem_ui_zoom) on that device only and is re-applied each time a UI loads. Useful on smaller iPhones where standard controls get cut off; reset to 100% to clear the override.
  • Mobile App — opens the QR code modal described in Mobile App
  • Change GEM Url — on iPad / Android / Capacitor shells, lets the user point the app at a different server

Default UI

UI with ID 0 is the system default. Users without a specific UI assignment see this UI.

UI Components

UIs are composed of:

  1. UI Controls - Navigation buttons/pages (see UI Controls)
  2. UI Zones - Zones assigned to this UI (see UI Zones)
  3. UI Macros - Macros accessible from this UI (see UI Macros)
  4. UI Pages - Custom pages with widgets (see UI Pages)
  5. Theme - Visual styling (see UI Themes)

Space-Linked vs Manual UIs

Every UI is either space-linked or manually composed. The distinction determines where its zones come from.

:::tip Default to space-linked In a well-organized install, most UIs can be built simply by assigning zones to Site Spaces — the space tree drives everything automatically. Reach for manual ui_zone composition only when the UI doesn't map to a physical space (building-wide dashboards, security panels, power-user consoles). :::

Space-Linked UIs (site_space_id is set)

The UI is bound to a Site Space via site_space_id. Zones are pulled live from zone.site_space_idno ui_zone rows are needed. Moving a zone into or out of the space makes it appear or disappear in the UI automatically.

  • include_child_spaces: false — show only zones in that exact space (default for rooms, kitchens, etc.)
  • include_child_spaces: true — include descendants as well, with each sub-space becoming a zone group (default for containers: building, floor, wing). The control pages also prepend an All group that aggregates zones across every child space.

:::tip Overlays Space-linked UIs can still take explicit UI Zone and UI Control rows — they're layered as overlays on top of the inherited set. Use them to add a zone or control that isn't in the space (e.g. a shared front-gate camera on every room panel), or to suppress an inherited control by adding a ui_control row with the same component and enabled = false. :::

Create a space-linked UI from the Site Spaces page with Create UI, or set site_space_id directly when creating a UI.

The side menu for a space-linked UI is auto-generated from the space's zones:

  • One control button per subsystem with zones in scope (lights, shades, climate, security, …).
  • AV is split: an Audio button appears only if at least one in-scope AV zone has av_type = audio, and a Video button only if at least one has av_type = video. Spaces with no AV zones get neither.
  • A Spaces button is appended whenever the space has child spaces, providing drill-down navigation to each child space's UI. Children without their own UI but with descendants that do are shown as drill-down tiles (label suffixed with ) — tapping descends one level deeper, and a breadcrumb with a back button lets you pop back out.

Manual UIs (site_space_id is null)

Zones come from explicit UI Zone rows and controls from UI Control rows. Nothing happens automatically. Use for:

  • Building-wide dashboards ("All Lights", "Security Panel", "HVAC Overview")
  • Power-user management consoles that mix zones from anywhere
  • Guest or role-restricted UIs with hand-picked zones

Common Workflows

Creating a Room Panel

For a kitchen wall tablet:

  1. Click Add
  2. Configure:
    Name: kitchen_panel
    Label: Kitchen Panel
    Group: main_floor
    Enabled: Yes
  3. Save and note the UI ID
  4. Navigate to UI > UI Zones and assign kitchen zones
  5. Navigate to UI > UI Controls and add relevant controls
  6. Navigate to UI > UI Themes and assign a theme
  7. Access via: https://gem.local/?ui=kitchen_panel

Creating a Mobile UI

For homeowner mobile app:

  1. Click Add
  2. Configure:
    Name: mobile_homeowner
    Label: Mobile - Homeowner
    Group: mobile
    Enabled: Yes
  3. Save
  4. Assign all necessary zones (all subsystems)
  5. Add all controls
  6. Set compact theme optimized for mobile
  7. In Attributes, set:
    compact_mode: true
    zones_per_row: 2

Creating a Guest UI

For limited guest access:

  1. Click Add
  2. Configure:
    Name: guest_panel
    Label: Guest Panel
    Enabled: Yes
  3. Save
  4. Assign only guest-accessible zones:
    • Guest bedroom lights
    • Guest bathroom lights
    • Common area lights
    • Temperature control
  5. Add limited controls (no admin, no advanced features)
  6. Create guest user account
  7. Restrict guest role to only this UI

Duplicating a UI

To create a similar UI:

  1. Edit existing UI
  2. Note all settings
  3. Create new UI
  4. Manually configure with similar settings
  5. Or export/import UI configuration (advanced)

Testing UIs

Open UI

Click the View icon to open the UI in a new browser tab:

  • Tests UI functionality
  • Verifies zone assignments
  • Checks theme application
  • Validates controls

Test Notifications

Click the Notification icon to test web push:

  • Sends test notification to connected clients
  • Verifies notification configuration
  • Tests notification delivery

Force Logout

Click the Logout icon to disconnect all clients:

  • Useful for testing login behavior
  • Forces UI reload
  • Clears client cache
  • All users connected to this UI will be logged out

UI Groups

Group UIs by category for organization:

Common Groups:

  • main_floor - Main floor panels
  • second_floor - Second floor panels
  • mobile - Mobile apps
  • guest - Guest interfaces
  • service - Service/installer interfaces

Groups appear in UI selectors and help organize large installations. Removing a group prompts for confirmation — UIs assigned to that group will become ungrouped.

Multiple UIs vs. Single UI

When to Use Multiple UIs

Good Reasons:

  • Different physical locations (room panels)
  • Different user types (owner vs. guest)
  • Different devices (tablet vs. phone)
  • Different themes per location
  • Site-specific configurations (multi-tenant)

Example:

UI 1: Kitchen Panel (kitchen zones only, bright theme)
UI 2: Bedroom Panel (bedroom zones only, dark theme)
UI 3: Mobile App (all zones, mobile-optimized theme)
UI 4: Guest Panel (limited zones, simplified interface)

When to Use Single UI

Good Reasons:

  • Simple installations
  • Consistent experience across devices
  • Centralized management
  • Minimal configuration

Use Roles Instead:

  • Different permissions for different users
  • Role-based access control handles restrictions
  • Single UI, multiple user roles

Security and Access

Role-Based UI Access

Control which users can access which UIs using Roles:

  1. Navigate to Security > Roles
  2. Edit or create a role
  3. In User Interfaces permissions:
    • Allow: Specific UI IDs
    • Deny: Restricted UI IDs
  4. Assign role to users

Example:

Guest Role:
Allow UI: guest_panel
Deny UI: all others

Result: Guests can only access guest_panel

Site-Based UI Access

For multi-site installations:

  1. Create UIs per site
  2. Assign UIs to appropriate sites (via attributes)
  3. Restrict users to specific sites

Advanced Topics

UI Reloading

Reload All Button:

  • Broadcasts reload command to all connected clients
  • Forces UI refresh
  • Useful after:
    • Theme changes
    • Major configuration updates
    • Zone additions
    • Control modifications

Individual UI Logout:

  • Disconnects clients from specific UI
  • Triggers automatic reload on next access
  • Less disruptive than Reload All

Web Push Notifications

Enable browser push notifications:

  1. Edit UI
  2. In Attributes, set web_push_enabled: true
  3. Clients will be prompted to allow notifications
  4. Test with notification icon in grid

Requirements:

  • HTTPS connection (SSL enabled)
  • Browser support (Chrome, Firefox, Safari 16+)
  • User permission granted

Dynamic UI Loading

UIs can load different configurations based on:

  • Query parameters
  • User roles
  • Time of day
  • System mode (home, away, vacation)

Configure via UI attributes and custom logic.

Embedded UIs

Embed GEM UIs in other applications:

<iframe src="https://gem.local/?ui=kitchen_panel&embed=true" />

Embed parameter removes navigation chrome for cleaner integration.

Troubleshooting

UI Not Showing Zones

Check:

  1. Zones assigned to UI in UI > UI Zones
  2. Zone groups configured correctly
  3. Subsystem enabled
  4. Zones enabled
  5. Device online

UI Shows Wrong Theme

Check:

  1. Theme attribute set for UI
  2. Theme files exist in /themes/{theme_name}/
  3. Browser cache cleared
  4. CSS file is valid

Cannot Access UI

Check:

  1. UI enabled
  2. User has role permission for UI
  3. Correct URL or UI parameter
  4. Network connectivity
  5. GEM server running

UI Not Reloading

Try:

  1. Force browser refresh (Ctrl+F5)
  2. Use Logout icon to disconnect
  3. Clear browser cache
  4. Use Reload All button