Show device state from the device API
Ta treść nie jest jeszcze dostępna w Twoim języku.
A dashboard can read the device API of an MC252 or MC261L on a PIN endpoint directly, without parameters in Setup. This guide builds a panel with the device’s network state and a clock synchronization button. The hooks are described in Dashboards: device API.
Read the device state
Section titled “Read the device state”-
Add the endpoint to the dashboard configuration in
config.ts:import Type from "typebox";export const dashboardConfigType = Type.Object({ endpointId: Type.Optional(Type.String({ format: "uuid", title: "MC252 endpoint" })) },{ additionalProperties: false },); -
Read the operation with
useDeviceApiRead, not withtrpc.device.api.invokein an effect. Shape the answer withselect. SetrefreshMsonly for values that change, and no shorter than the dashboard needs; each read counts toward the operation’s rate limit, which every viewer of the endpoint shares. -
Check the endpoint with
useDeviceApi(endpointId). When itsstatusisunsupported, hide the device panel. When a read isunavailable, show a message instead of the value. -
Show
deviceApiErrorText(error)for a failed read.
Add a device action
Section titled “Add a device action”- Call the operation with
useDeviceApiAction, and show the button only whileavailableis true. The viewer’s role decides which operations they get. - Before a call that is hard to undo, ask for confirmation in the dashboard, for example with
AlertDialogfrom@overvis/hmi-workspace-ui/ui. - Show
deviceApiErrorText(error)when the call fails.
Example: MC252 state
Section titled “Example: MC252 state”This dashboard shows the Ethernet and VPN state of an MC252 every 30 seconds. Editors, admins and
owners also get a button that resynchronizes the device clock; operators do not see it, because
time.sync needs an editor. index.tsx:
import { parseDashboardConfiguration, type DashboardRootProps,} from "@overvis/hmi-shared/dashboard";import { deviceApiErrorText, useDeviceApiAction, useDeviceApiRead,} from "@overvis/hmi-workspace-ui";import { Button, Card, CardContent, CardHeader, CardTitle } from "@overvis/hmi-workspace-ui/ui";import type { ReactElement } from "react";import { dashboardConfigType } from "./config.ts";
export { dashboardConfigType } from "./config.ts";export const supportedLocales = ["en"] as const;
const member = (value: unknown, key: string): unknown => typeof value === "object" && value !== null ? Reflect.get(value, key) : undefined;const text = (value: unknown): string => typeof value === "string" || typeof value === "number" ? String(value) : "–";
/** The parts of the `state.get` answer this dashboard shows. */function toState(response: unknown) { const ethernet = member(response, "ethernet"); const vpn = member(response, "vpn"); return { linkUp: member(ethernet, "linkUp") === true, ip: text(member(ethernet, "ip")), vpnState: text(member(vpn, "linkState")), vpnIp: text(member(vpn, "netifIp")), };}
export default function Mc252StateDashboard(props: DashboardRootProps): ReactElement { const { endpointId } = parseDashboardConfiguration(dashboardConfigType, props.configuration); const state = useDeviceApiRead({ endpointId, operation: "state.get", input: { query: { ethernet: true, vpn: true } }, refreshMs: 30_000, select: toState, }); const sync = useDeviceApiAction({ endpointId, operation: "time.sync" });
if (state.status === "unavailable") return <p className="p-4">No device state for this endpoint.</p>; return ( <main className="grid gap-4 p-4 md:grid-cols-2"> <Card> <CardHeader> <CardTitle>Ethernet</CardTitle> </CardHeader> <CardContent> {state.data?.linkUp === true ? "Link up" : "No link"} · {state.data?.ip} </CardContent> </Card> <Card> <CardHeader> <CardTitle>VPN</CardTitle> </CardHeader> <CardContent> {state.data?.vpnState} · {state.data?.vpnIp} </CardContent> </Card> {state.error != null ? ( <p className="text-sm text-destructive md:col-span-2">{deviceApiErrorText(state.error)}</p> ) : null} {sync.available ? ( <div className="flex items-center gap-3 md:col-span-2"> <Button disabled={sync.isPending} onClick={() => void sync.call().catch(() => undefined)} > Synchronize clock </Button> {sync.error != null ? ( <span className="text-sm text-destructive">{deviceApiErrorText(sync.error)}</span> ) : null} </div> ) : null} </main> );}To translate the labels, follow Localize a dashboard.
Page through a journal
Section titled “Page through a journal”lorasens.journal.read on an MC261L returns up to five journal files of sensor records received
after after: from, till, and records. To read the next page, read again from the returned
till:
const [after, setAfter] = useState<string | null>(null);const journal = useDeviceApiRead({ endpointId, operation: "lorasens.journal.read", input: after == null ? {} : { query: { after } }, select: (response) => { const till = member(response, "till"); const records = member(response, "records"); return { till: typeof till === "string" ? till : null, records: Array.isArray(records) ? records : [], }; },});// Show journal.data?.records; a "Newer records" button calls setAfter(journal.data.till).Going back to an earlier page shows it without another call while it is fresh.
Test the dashboard
Section titled “Test the dashboard”The assistant’s dashboard preview calls read operations only. A write there fails with
push_agent_key, so test actions in the published dashboard.