Input types
Every preference input type, how it hydrates, and the input / section / page definition fields.
Types
Types marked as hydrated become globalThis.<key> bindings before each handler runs; the others are only reachable through settings. default is a form default — it is never applied at hydration, so code must handle undefined.
| Type | Hydrated as | Notes |
|---|---|---|
string | string | Single-line text. |
number | number literal | Numeric value; honours minValue / maxValue / unit. |
boolean | boolean literal | On/off toggle. |
enum | string | One of options; renders as a dropdown or tiles (widget). |
date | string | Calendar date as an ISO string. |
object | not hydrated (read from settings) | Nested object; reachable only through settings. |
array | JSON array (rows are plain objects) | Repeating rows described by itemSchema. |
text | string | Multi-line text. |
password | string | Masked text; stored as a plain string. |
email | string | Email address; validated on submit. |
time | string | Time of day as HH:mm. |
entity | EntityWrapper (one pick) or a Proxy array of EntityWrappers (2+ picks, fans every service call out to all members) | Device picker; narrowed with domainFilter / deviceClassFilter; multiple allows several. |
domain | not hydrated (read from settings) | Entity-domain picker (e.g. light). |
mode | not hydrated (read from settings) | Location mode picker. |
hub | not hydrated (read from settings) | Hub picker. |
app | not hydrated (read from settings) | Child smart-app picker (childRef names the child definition). |
accountUserEmail | not hydrated (read from settings) | Account user, stored as their email. |
accountUserPhone | not hydrated (read from settings) | Account user, stored as their phone number. |
accountUserId | not hydrated (read from settings) | Account user, stored as their user id. |
thermostatSchedule | JSON array (rows are plain objects) | Weekly 7×24 schedule grid; stored like array. |
Input definition
Fields of an entry in a page's inputs (or a section's).
| Field | Type | Optional | Description |
|---|---|---|---|
key | string | no | — |
label | string | no | — |
type | DataType | no | — |
required | boolean | yes | — |
default | unknown | yes | — |
description | string | yes | — |
options | EnumOption[] | yes | — |
visible | Condition | yes | — |
submitOnChange | boolean | yes | — |
multiple | boolean | yes | — |
minValue | number | yes | — |
maxValue | number | yes | — |
unit | string | yes | Canonical unit of a numeric value (e.g. '°C'). User clients render the input in the location display unit and convert display↔canonical; the admin SPA renders canonical units. |
unitFromEntity | string | yes | — |
domainFilter | string | yes | Entity-picker filters. The hub normalizes legacy filter: { domain, deviceClass } from smart-app source into these two scalars. |
deviceClassFilter | string | yes | — |
placeholder | string | yes | — |
readonly | boolean | yes | — |
itemSchema | { inputs: ClientInputDefinition[] } | yes | — |
minItems | number | yes | — |
maxItems | number | yes | — |
itemSummaryKeys | string[] | yes | UI hint: item-field keys (in order) shown in a collapsed array row's one-line summary. When omitted, the summary is derived from filled fields. |
childRef | { namespace: string; name: string } | yes | 'app'-type input. Points at a sibling smart-app definition by (namespace, name). The client renders the input as a list of currently- installed children of the calling parent matching this ref + an "Add new" button that opens a child install dialog. |
filterOptionsByEntityDomain | string | yes | Per-row option filter for enum inputs inside an array's itemSchema. When set, the array editor filters this input's options per row to entries whose value starts with <domain>. where <domain> is the entity-domain of the sibling input named here. No-op for inputs at the top level (not inside an array). |
requiresEntityFeature | { siblingKey: string; domain?: string | string[]; // Inverse of 'domain': hide when the sibling entity's domain matches // any of these. Useful when "show for everything except SENSOR" is // easier than listing every typed-state domain. domainNotEquals?: string | string[]; featureBit?: number; colorMode?: string; } | yes | Per-row visibility gate. The array editor hides this input unless the sibling input identified by siblingKey resolves to an entity that satisfies every constraint set. See FormEngine.InputDefinition for the full semantics; mirrored here verbatim. |
requiresSiblingOneOf | { siblingKey: string; values: string[] } | yes | Simpler sibling-value gate. Input is hidden unless the named sibling's value appears in values. Composes (AND) with requiresEntityFeature when both are set. |
filterOptionsBySiblingPrefix | string | yes | Filter this enum's options by sibling's raw value used as a prefix with a trailing dot (option.value.startsWith(${sibling}.)). |
domainFilterFrom | string | yes | For entity inputs inside an array, pull the entity-domain filter from the named sibling's value at render time rather than the static domainFilter field. |
widget | 'dropdown' | 'tiles' | 'textarea' | yes | Render-style hint. 'tiles' switches an enum's dropdown for a card grid with title + description. 'textarea' switches a string input for a multi-line text area. Anything else uses the type's default renderer. |
Section definition
| Field | Type | Optional | Description |
|---|---|---|---|
id | string | no | — |
title | string | yes | — |
inputs | ClientInputDefinition[] | no | — |
visible | Condition | yes | — |
Page definition
| Field | Type | Optional | Description |
|---|---|---|---|
id | string | no | — |
title | string | no | — |
description | string | yes | Page-level banner text shown above the inputs. Used by integrations like the LAN-discovery wizards for an intro page explaining what's about to happen ("Novon will scan your LAN for ..."). Optional — most pages omit it. |
loadingDescription | string | yes | Client-facing loading text rendered as the spinner caption WHILE the engine is transitioning TO this page and the hub is running a prepareSchemaForPage hook. Used by the picker page of LAN-discovery wizards ("Scanning your LAN for ..."). The caller reads this BEFORE submitting, so it knows the message immediately. |
inputs | ClientInputDefinition[] | yes | — |
sections | ClientSectionDefinition[] | yes | — |
visible | Condition | yes | — |
Conditions
visible on inputs and sections takes a condition. Operators: equals, notEquals, greaterThan, lessThan, greaterThanOrEqual, lessThanOrEqual, contains, in, truthy, falsy.
export interface SimpleCondition {
input: string;
operator: ConditionOperator;
value?: unknown;
}
export interface CompoundCondition {
and?: Condition[];
or?: Condition[];
}