Skip to main content

Hooks

React hooks that connect your components to live device data. All hooks require your app to be wrapped in RelayProvider.

useRelayApp()

Access the raw App SDK instance.

import { useRelayApp } from "@relay-x/ui";

const app = useRelayApp(); // RelayAppInstance | null

useRelayConnection()

Access the App SDK instance and connection status.

import { useRelayConnection } from "@relay-x/ui";

const { app, isConnected, error } = useRelayConnection();
ReturnTypeDescription
appobject | nullThe App SDK instance
isConnectedbooleanWhether the SDK is connected
errorstring | nullError message if connection failed (e.g., auth_failed)

useRelayTimeSeries()

Stream historical and/or real-time telemetry data for a device.

import { useRelayTimeSeries } from "@relay-x/ui";

const { data, isLoading, error } = useRelayTimeSeries({
deviceIdent: "sensor_01",
metrics: ["temperature", "humidity"],
mode: "both",
timeRange: {
start: Date.now() - 3600000,
end: Date.now(),
},
});

Options

OptionTypeDescription
deviceIdentstringThe device identifier
metricsstring[]Metrics to subscribe to
modestring"historical", "realtime", or "both". Default: "historical"
timeRangeobject{ start: number, end: number } — timestamps in ms
maxPointsnumber(optional) Maximum data points to keep. Default: 10000
intervalstring(optional) Bucket size as a Flux duration ("30s", "5m", "1h"). Pair with aggregateFn. Historical only
aggregateFnstring(optional) Server-side aggregation. One of "mean", "min", "max", "sum", "count", "first", "last", "median", "stddev". Pair with interval. Historical only

interval and aggregateFn are passed through to the App SDK as interval and aggregate_fn. Both must be set together to produce bucketed results. They have no effect when mode is "realtime", since live points stream as they arrive.

Modes

ModeBehavior
"historical"Fetches data once for the given time range. No live updates.
"realtime"Streams live data only. No historical data.
"both"Fetches historical data first, then streams live updates. New data is merged in.

Return

ReturnTypeDescription
dataDataPoint[]Array of data points with merged metrics
isLoadingbooleantrue while fetching historical data
errorError | nullError if the fetch or stream failed

useRelayLatest()

Get the most recent value for a single metric. Fetches the latest and subscribes to live updates. Returns a RelayDataPoint that can be passed directly to any component's data prop.

import { useRelayLatest } from "@relay-x/ui";

const latest = useRelayLatest({
deviceIdent: "sensor_01",
metric: "temperature",
timeRange: {
start: Date.now() - 86400000,
end: Date.now(),
},
});

// Pass directly to a component
<NeedleGauge data={latest} min={0} max={100} />

Options

OptionTypeDescription
deviceIdentstringThe device identifier
metricstringThe metric name
timeRangeobject{ start: number, end: number } — timestamps in ms

Return (RelayDataPoint)

ReturnTypeDescription
valuenumber | nullThe latest metric value
timestampnumber | nullWhen the value was recorded (ms)
isLoadingbooleantrue while fetching
errorError | nullError if the fetch or stream failed

Components that accept a data prop (NeedleGauge, ArcGauge, ProgressBar, StatCard, StatCardWithGraph) expect this exact shape.

useRelayEvents()

Subscribe to historical and/or real-time events for a device.

import { useRelayEvents } from "@relay-x/ui";

const { data, isLoading, error } = useRelayEvents({
deviceIdent: "sensor_01",
eventNames: ["door_opened", "door_closed"],
mode: "both",
timeRange: {
start: Date.now() - 86400000,
end: Date.now(),
},
});

Options

OptionTypeDescription
deviceIdentstringThe device identifier
eventNamesstring[]Event names to subscribe to
modestring"historical", "realtime", or "both". Default: "historical"
timeRangeobject{ start: number, end: number }

Return

ReturnTypeDescription
dataRelayEvent[]Events sorted ascending by timestamp
isLoadingbooleantrue while fetching historical data
errorError | nullError if the fetch or stream failed

Each RelayEvent has name, deviceIdent, value, and timestamp (Unix ms).

useRelayLogs()

Subscribe to historical and/or real-time device logs, with optional level filtering.

import { useRelayLogs } from "@relay-x/ui";

const { data, isLoading, error } = useRelayLogs({
deviceIdent: "sensor_01",
levels: ["warn", "error"],
mode: "realtime",
timeRange: {
start: Date.now() - 3600000,
end: Date.now(),
},
});

Options

OptionTypeDescription
deviceIdentstringThe device identifier
levelsstring[](optional) Subset of ["info", "warn", "error"]. Omit for all levels
modestring"historical", "realtime", or "both". Default: "historical"
timeRangeobject{ start: number, end: number }

Return

ReturnTypeDescription
dataRelayLog[]Logs sorted ascending by timestamp
isLoadingbooleantrue while fetching historical data
errorError | nullError if the fetch or stream failed

Each RelayLog has deviceIdent, level ("info" \| "warn" \| "error"), message, and timestamp (Unix ms).

useRelayCommands()

Fetch command history for one or more devices. Polls on a configurable interval since there is no live command stream.

import { useRelayCommands } from "@relay-x/ui";

const { data, isLoading, error, refresh } = useRelayCommands({
name: "set_brightness",
deviceIdents: ["sensor_01", "sensor_02"],
timeRange: {
start: Date.now() - 86400000,
end: Date.now(),
},
refreshInterval: 30000,
});

Options

OptionTypeDescription
namestringThe command name
deviceIdentsstring[]Device identifiers to query
timeRangeobject{ start: number, end: number }. With refreshInterval, end slides to "now" on each tick
refreshIntervalnumber(optional) ms between re-fetches. Omit for a one-shot query

Return

ReturnTypeDescription
dataRelayCommand[]Commands sorted ascending by timestamp
isLoadingbooleantrue while fetching
errorError | nullError if the fetch failed
refreshfunctionTrigger an immediate re-fetch without waiting for the next tick

Each RelayCommand has name, deviceIdent, value, and timestamp.

useRelayAlerts()

Org-wide alert event feed. Returns a flat list of fire, resolved, and ack events that you can reduce by incident_id to render an incident-level UI.

import { useRelayAlerts } from "@relay-x/ui";

const { data, isLoading, error } = useRelayAlerts({
mode: "both",
filters: {
deviceIdents: ["sensor_01", "sensor_02"],
},
timeRange: {
start: Date.now() - 86400000,
end: Date.now(),
},
});

Options

OptionTypeDescription
modestring"historical", "realtime", or "both". Default: "historical"
filters.ruleIdsstring[](optional) Match by rule id
filters.deviceIdentsstring[](optional) Match by device identifier
filters.groupIdsstring[](optional) Match by logical or hierarchy group. Stream-only — not applied to historical results
timeRangeobjectRequired for "historical" and "both". Ignored for "realtime"

Return

ReturnTypeDescription
dataRelayAlertEvent[]Alert events with snake_case keys
isLoadingbooleantrue while fetching historical data
errorError | nullError if the fetch or stream failed

Each RelayAlertEvent has state ("fire" \| "resolved" \| "ack"), rule_id, rule_name, rule_type, device_id, device_ident, incident_id, timestamp, and an ack object on ack events. Stream events arrive pre-enriched, so rule_name, rule_type, and device_ident are populated without extra lookups.

Page-load reconciliation

In "both" mode, history loads silently to populate the current incident state, then the live stream takes over from now. If you trigger browser notifications or sounds from the data, gate them on event.timestamp > pageLoadTime so the silent reconciliation does not re-trigger alerts that already happened.

Custom notifications after ack

fire events keep arriving on the cooldown after an incident is acknowledged — the alerting engine continues publishing them for the audit trail. If you dispatch your own notifications from the alert feed, track ack state per incident_id and skip dispatch while the incident is in acknowledged. See the App SDK alerts reference for the full behavior.

useRelayPresence()

Track whether a device is online or offline.

import { useRelayPresence } from "@relay-x/ui";

const { online, lastEvent, isLoading, error } = useRelayPresence("sensor_01");

Return

ReturnTypeDescription
onlineboolean | nulltrue if online, false if offline, null if unknown
lastEventobject | nullLast presence event with device_ident and event type
isLoadingbooleantrue while initial presence is being determined
errorError | nullError if the presence subscription failed