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 Spaceis 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
labelcolumn viaformatLabel(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_TV→Kitchen TV,master_BR→Master BR), but longer all-caps words are Title Cased to tame shouting (KITCHEN→Kitchen,MAIN_LOFT→Main 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 alabelcolumn. - 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:
- Click Add in the grid toolbar
- The UI editor opens with two tabs: UIs and Attributes
- Configure the UI properties (see sections below)
- 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 actiongallery- Show photo gallery/screensaverlogout- Log out usergoto_page- Navigate to specific page
Navigation:
default_page- Page to show on loginhome_button_action- What home button doesback_button_enabled- Show/hide back button
Layout:
zones_per_row- Number of zones per row in grid layoutscompact_mode- Reduced spacing for smaller screensshow_labels- Show/hide zone labels
Sorting:
ui_group_sort- How zone groups are sorted in control pages. Set toalphabeticalto sort groups by name instead of the default sort index order.
Notifications:
web_push_enabled- Enable browser push notificationsnotification_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. Default5000. 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 thelutron_qsxdevice'ssync_areascommand for any UI whosesite_space_idmatches a Lutron area that has control stations. When edited manually, the attribute editor shows a station picker (with area name) sourced live from thelutron_qsxdriver 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_keyingem.jsonor theanthropic_api_keysystem 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
groupvalue from non-space-linked UIs becomes a drill-down tile (suffixed with›). Group order honorssettings.ui_groupsif set, otherwise falls back to the smallest membersort_index. - Ungrouped manual UIs — UIs with no
site_space_idand nogroupshow 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 inlocalStorage(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:
- UI Controls - Navigation buttons/pages (see UI Controls)
- UI Zones - Zones assigned to this UI (see UI Zones)
- UI Macros - Macros accessible from this UI (see UI Macros)
- UI Pages - Custom pages with widgets (see UI Pages)
- 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_id — no 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 hasav_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:
- Click Add
- Configure:
Name: kitchen_panelLabel: Kitchen PanelGroup: main_floorEnabled: Yes
- Save and note the UI ID
- Navigate to UI > UI Zones and assign kitchen zones
- Navigate to UI > UI Controls and add relevant controls
- Navigate to UI > UI Themes and assign a theme
- Access via:
https://gem.local/?ui=kitchen_panel
Creating a Mobile UI
For homeowner mobile app:
- Click Add
- Configure:
Name: mobile_homeownerLabel: Mobile - HomeownerGroup: mobileEnabled: Yes
- Save
- Assign all necessary zones (all subsystems)
- Add all controls
- Set compact theme optimized for mobile
- In Attributes, set:
compact_mode: truezones_per_row: 2
Creating a Guest UI
For limited guest access:
- Click Add
- Configure:
Name: guest_panelLabel: Guest PanelEnabled: Yes
- Save
- Assign only guest-accessible zones:
- Guest bedroom lights
- Guest bathroom lights
- Common area lights
- Temperature control
- Add limited controls (no admin, no advanced features)
- Create guest user account
- Restrict guest role to only this UI
Duplicating a UI
To create a similar UI:
- Edit existing UI
- Note all settings
- Create new UI
- Manually configure with similar settings
- 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 panelssecond_floor- Second floor panelsmobile- Mobile appsguest- Guest interfacesservice- 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:
- Navigate to Security > Roles
- Edit or create a role
- In User Interfaces permissions:
- Allow: Specific UI IDs
- Deny: Restricted UI IDs
- 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:
- Create UIs per site
- Assign UIs to appropriate sites (via attributes)
- 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:
- Edit UI
- In Attributes, set
web_push_enabled: true - Clients will be prompted to allow notifications
- 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:
- Zones assigned to UI in UI > UI Zones
- Zone groups configured correctly
- Subsystem enabled
- Zones enabled
- Device online
UI Shows Wrong Theme
Check:
- Theme attribute set for UI
- Theme files exist in
/themes/{theme_name}/ - Browser cache cleared
- CSS file is valid
Cannot Access UI
Check:
- UI enabled
- User has role permission for UI
- Correct URL or UI parameter
- Network connectivity
- GEM server running
UI Not Reloading
Try:
- Force browser refresh (Ctrl+F5)
- Use Logout icon to disconnect
- Clear browser cache
- Use Reload All button