UI Controls
UI Controls are navigation buttons and pages that appear in the main navigation of each UI. They determine which control pages (Lighting, AV, HVAC, etc.) are accessible from each user interface.
Overview
UI Controls allow you to:
- Customize which control pages appear in each UI
- Create UI-specific controls (hide irrelevant controls)
- Configure control icons and labels
- Reorder navigation buttons
- Set PIN protection for specific controls
Viewing UI Controls
The page has two tabs: List and Select.
List Tab
The main grid displays all UI controls with the following columns:
- ID - Unique identifier
- Label - Display text on navigation button
- Component - Svelte component path
- UI - UI this control belongs to (null = global)
- Icon - Icon filename
- PIN - Whether PIN is required to access
- Enabled - Whether the control is active
- Sort Index - Display order
Grid Actions
- Add - Create a new UI control
- Delete - Remove a UI control
- Sort - Reorder controls by dragging rows
Quick Actions
- Duplicate Icon - Copy an existing control
Understanding Global vs. UI-Specific Controls
Global Controls (UI = null)
- Appear in ALL UIs by default
- Cannot be removed from a specific UI
- Include standard controls: Lighting, Audio, Video, Climate
UI-Specific Controls (UI = specific ID)
- Appear only in the assigned UI
- Override global controls when present
- Allow per-UI customization
Hiding Global Controls
To hide a global control from a specific UI:
- Click Duplicate icon on the global control
- Set UI to the target UI ID
- Set Enabled = No
- Save
Result: The disabled UI-specific control overrides the global control, effectively hiding it from that UI.
Tip: A tooltip on the List tab explains this: "To hide a global control, copy it, add it to a specific UI, then disable it"
Space-Linked UIs
When a UI has site_space_id set, its control list is auto-derived from the subsystems present in the linked Site Space (and descendants if include_child_spaces is on). ui_control rows on a space-linked UI are still honored as overlays:
- A row with a new
componentadds a control on top of the inherited set. - A row with the same
componentas an inherited control andenabled = falsesuppresses that inherited control.
The Select tab shows a banner reminding you of this when a space-linked UI is selected.
Select Tab
The Select tab provides a quick way to add standard controls to a UI:
Workflow
Left Side - Available Controls:
- Lists all subsystem-based controls
- Includes: Lighting, Shades, Security, HVAC, etc.
- Plus special controls: Audio, Video
Center - Action Buttons:
- Add ▶ - Add selected controls to UI
- ◀ Remove - Remove selected controls from UI
Right Side - Current UI Controls:
- Shows controls already assigned to selected UI
- Sorted by sort_index
Using the Select Tab
- Select a UI from the dropdown at the top
- Choose controls from the left list (multi-select)
- Click Add ▶ to add them to the UI
- Or select existing controls on the right and click ◀ Remove
Component Path: Controls are automatically mapped to /controls/{subsystem_lowercase}
Example:
Lighting → /controls/lighting
Audio → /controls/audio
Shades → /controls/shades
Control Configuration
Basic Properties
Label
- Text shown on navigation button
- Examples: "Lighting", "Audio", "Climate", "Cameras"
- Can be customized per UI
Component
- Svelte component path
- Must start with
/ - Standard format:
/controls/{name} - Custom components:
/controls/custom_control
UI
- Leave blank for global control (all UIs)
- Select specific UI for UI-only control
- Use for UI customization
Icon
- Icon filename (without extension)
- Located in theme's
/icons/directory - Examples:
lighting,audio,shades,security - If not set, defaults based on component name
PIN
- Require PIN entry before accessing control
- Useful for:
- Parental controls
- Secure controls (security system)
- Administrative functions
Enabled
- Toggle to show/hide control
- Disabled controls don't appear in navigation
- Configuration preserved
Sort Index
- Display order in navigation
- Lower numbers appear first
- Drag rows in the grid, then click the Save Sort Order button (swap-sort icon) in the toolbar to renumber
Common Use Cases
Adding Standard Controls to a UI
Using Select tab:
- Select UI:
kitchen_panel - Select controls: Lighting, Shades, Climate
- Click Add ▶
- Controls appear in kitchen panel navigation
Creating Custom Control
- Switch to List tab
- Click Add
- Configure:
Label: SecurityComponent: /controls/securityUI: master_bedroom_panelIcon: shieldPIN: Yes (require PIN)Enabled: Yes
- Save
Hiding Global Control from Specific UI
To hide "Video" from guest panel:
- Find "Video" global control in list
- Click Duplicate icon
- In the copy, set:
UI: guest_panelEnabled: No
- Save
- Video control no longer appears in guest_panel
Reordering Controls
Using List tab:
- Enable Sort action
- Drag controls to desired order
- Sort index updates automatically
- Changes take effect immediately in UIs
Or using Select tab (right side):
- Select a control from the right list
- Use ▲ ▼ buttons to move up/down
- Sort index updates automatically
PIN-Protected Controls
For secure access to certain controls:
- Edit the control (e.g., "Security")
- Set PIN: Yes
- Save
- When users click the control:
- PIN prompt appears
- Must enter valid PIN (from user account)
- On success, control opens
- On failure, access denied
Control Components
Standard Control Components
GEM includes built-in control components:
/controls/lighting
- Zone grid for lighting control
- Supports on/off, dimming, color
- Scene buttons if configured
/controls/audio
- Audio zone control
- Volume, input selection, transport
- Multi-room audio grouping
/controls/video
- Video zone control
- Source selection, display control
- AV matrix routing
/controls/shades
- Shade position control
- Open, close, stop, presets
- Group control
/controls/climate
- Thermostat control
- Temperature, mode, fan
- Multi-zone HVAC
/controls/security
- Alarm panel interface
- Arm, disarm, status
- Zone bypass
/controls/cameras
- Camera feeds
- PTZ control
- Recording playback
/controls/garage
- Garage door control for the
garagesubsystem — All / None selection, then raise or close the selected doors - Handles two opener styles automatically per zone:
- Pulse-relay doors (a single momentary contact that toggles the door) — raise/close only fire when the door isn't already where you want it, and press-and-hold the raise/close button forces a pulse regardless of the sensed state (escape hatch for a wrong door sensor)
- Discrete openers (separate open/close/stop, e.g. Konnected) — raise/close send the verb directly and idempotently (no toggle guard); a Stop button appears whenever any door in the fleet supports a real mid-travel stop
- Opener style is detected from the zone's
open_action/close_action/stop_actionattributes — discrete openers carry these (stamped by their driver), pulse-relay doors do not and fall back topulse. See Command Overrides - Renders an interactive zone map when garage zones are placed on a map (see UI Themes → Zone Maps); otherwise falls back to an inline camera feed alongside a row of labeled zone-select buttons, one per door
- Each zone-select button shows the door's live status as a colored badge below its label — opening / closing in blue while the door is travelling (from the zone's
operationattribute), open in amber (worth noticing), and closed in green (secured). Relay-only doors that don't report an operation show just open/closed - The inline camera feed is sourced from the
camera_zoneattribute on thegaragesubsystem - The camera-feed fallback is orientation-aware — the camera occupies half the width in landscape and the full width in portrait
/controls/doors
- Door and lock control for the
doorsubsystem — a grid of zone-select tiles (one per door or lock) alongside the selected zone's full control panel - Each tile shows the door's live state and battery level as a colored badge below its label, updated in real time via zone subscriptions:
- closed / locked in green (secured)
- open / unlocked / ajar in amber (worth noticing)
- opening / closing / moving in blue (in motion)
- fault / alarm / error / offline in red
- any other state falls back to the generic status colors
- When a zone reports a battery level it is appended to the badge as a percentage (e.g.
closed - 87%) - This live badge now renders for every subsystem that uses the generic zone-grid control (doors, gates, covers, power, water, fire, lift, fans, …), driven by each zone's
stateand battery (battery_level/battery) attributes via live subscriptions. A zone that reports neither simply shows a plain label, so subsystems whose zones don't publish state are unaffected
/controls/water
- Water management control
- Leak sensors, shut-off valves
- Flow monitoring
/controls/weather
- Weather station data
- Temperature, humidity, wind
- Forecast display
/controls/pool
- Pool equipment control
- Temperature, pumps, lights
- Spa control
/controls/spaces
- Drill-down tile grid for child site spaces
- Auto-included in space-linked UI menus when the bound space has children with their own UIs (or descendants further down that do)
- Tile behavior:
- Leaf tile — child has its own UI. Tapping navigates to that UI.
- Drill-down tile (label ends with
›) — child has no UI of its own but a descendant does. Tapping descends into that child and re-loads the tile grid from its children.
- A breadcrumb with a ‹ Back button appears once you've drilled in, popping one level at a time back to the original UI's space
Custom Control Components
Create custom control components:
- Develop Svelte component in
src/components/controls/ - Add route in
src/routes/controls/ - Create UI control pointing to the component
- Assign to UI
Example Custom Control:
<!-- src/routes/controls/outdoor_audio.svelte -->
<script>
import GemApp from '../../gem/app';
// Custom outdoor audio control logic
</script>
<div class="outdoor-audio-control">
<!-- Custom UI for outdoor audio zones -->
</div>
Then create UI control:
Label: Outdoor Audio
Component: /controls/outdoor_audio
Icon: speaker_outdoor
Icons
Icons are stored in the theme's /icons/ directory:
Standard Icons
lighting- Light bulbaudio- Speakervideo- TV/displayshades- Window blindsclimate- Thermometersecurity- Shieldcamera- Camerapool- Poolirrigation- Sprinklerlock- Padlock
Custom Icons
Upload custom icons via UI > UI Themes page:
- Navigate to UI > UI Themes
- Select theme
- Go to Icons tab
- Upload PNG or SVG files
- Reference by filename in UI Control
Icon Requirements:
- Format: PNG or SVG
- Size: 64x64 to 128x128 pixels
- Style: Should match theme aesthetic
- Filename: lowercase_with_underscores.png
Best Practices
-
Consistent Labeling: Use clear, recognizable names for controls
-
Logical Ordering: Arrange controls by frequency of use:
- Most used first (Lighting, Audio)
- Moderate use middle (Climate, Shades)
- Least used last (Pool, Irrigation)
-
Icon Selection: Choose icons that clearly represent the control function
-
Global Defaults: Use global controls for controls that should appear everywhere
-
UI Overrides: Use UI-specific controls sparingly, only when truly needed
-
PIN Protection: Only PIN-protect controls that need security:
- Security system
- Administrative functions
- Potentially dangerous controls (gates with traffic)
-
Testing: Test controls after adding to verify component exists and loads
-
Enabled State: Disable rather than delete during troubleshooting
Troubleshooting
Control Not Appearing
Check:
- Enabled: Control must be enabled
- UI Assignment: Control is global OR assigned to this UI
- Component Exists: Svelte component file exists at path
- UI Enabled: Parent UI must be enabled
- Role Permission: User's role allows access to this UI
Control Shows Error
Check:
- Component Path: Must start with
/ - Component Exists: File exists at
src/routes/controls/{name}.svelte - Syntax Errors: Component has valid Svelte syntax
- Console Errors: Check browser console for runtime errors
Wrong Icon Displays
Check:
- Icon Name: Matches file in theme's
/icons/directory - Theme: Correct theme assigned to UI
- File Extension: Don't include .png or .svg in icon name
- Browser Cache: Clear cache and reload
PIN Not Working
Check:
- User PIN: User has PIN set in user account
- PIN Match: Entered PIN matches user PIN
- Case Sensitivity: PINs are typically numeric (no case)
Duplicate Not Working
Cause: Duplicate creates a copy but doesn't auto-save
Solution: After clicking duplicate, configure the new control and save explicitly
Advanced Topics
Conditional Controls
Show/hide controls based on system state:
Not directly supported in UI Controls page. Implement via:
- Custom control component with conditional display
- JavaScript in theme
- Macro that enables/disables controls
Dynamic Control Counts
Display count badges on controls:
Example: Show number of lights that are on
Implement in control component:
let onCount = zones.filter(z => z.power === 'on').length;
Control Templates
For installations with many similar UIs:
- Create template UI with all desired controls
- Duplicate UI
- Modify specific controls as needed
- Saves time vs. configuring from scratch