Przejdź do głównej zawartości

Build a dashboard for one device model

Ta treść nie jest jeszcze dostępna w Twoim języku.

A dashboard for one device model combines the same parts every time: pages under one header with live controls, two polling cohorts, a banner when the device connection is down, and trends of the main readings. This guide puts them together. Each component is described in Device dashboard components.

  1. Wrap the dashboard in DevicePresetLayout. Give each page an id, a path, a label, the readings it polls (fastIds), and the settings it polls (slowIds):

    <DevicePresetLayout
    id="pump-controller-dashboard"
    title={copy.title}
    subtitle={copy.subtitle}
    image={{ src: photoUrl, alt: copy.frontPanel }}
    workspaceId={props.workspaceId}
    dashboardId={props.dashboardId}
    pages={[
    { id: "overview", path: "/", label: copy.overview, fastIds: readingIds, slowIds: [] },
    {
    id: "settings",
    path: "/settings",
    label: copy.settings,
    fastIds: [],
    slowIds: settingIds,
    },
    ]}
    >
    {({ page, connected, readAgain }) =>
    page === "overview" ? (
    <Overview connected={connected} />
    ) : (
    <Settings connected={connected} onReadAgain={readAgain} />
    )
    }
    </DevicePresetLayout>
  2. Put registers that some firmware versions lack in optionalIds. Where such a reading appears, show it as not supported when isUnsupportedParameterValue(state) is true.

  3. For a banner that applies on every page, such as a device mode the operator should end, use notices. Add the values the notice reads to every page’s fastIds or slowIds.

  4. If the dashboard needs another frame, build it from useDevicePresetValues, DevicePresetHeader with the compact ParameterLiveControls, DashboardPageTabs, DeviceEndpointUnavailable, and ParameterDiagnostics. For several devices, call useDevicePresetValues once per device.

  1. Show each reading as its parameter formats it, with ParameterValueDisplay without children, and take its unit from useParameterUnit(parameterId, locale). The dashboard then follows the scaling and units configured on the parameters instead of repeating them.
  2. For a trend, pass the series to ParameterTrendChart. Set followClock to true when the reading is not fresh, so a stalled reading shows as a trailing gap.
  3. When the operator can hide series, pass each series’ colorIndex, so it keeps its color.
  1. Put a DeviceStatusBar of DeviceStatusBadges at the top, then a column of cards.
  2. Show headline values with DeviceKeyFigure, and frame everything else in DevicePanels.
  3. Show phase readings in DevicePhaseTable and other readings in DeviceReadingList; tables with the same columns line up.
  4. Order the page for a phone user: put active faults and commands before the long tables.
  5. Place the cards in columns on wide screens with container queries.
  1. Poll the settings in the slow cohort of the page that shows them. DeviceSettingsSection shows only values that the page already polls.

  2. Add one DeviceSettingsSection per group of settings, with keys, bindings, labels, and a specs entry for each key:

    <DeviceSettingsSection
    id="power-limit"
    icon={<GaugeIcon />}
    title={copy.powerLimit}
    description={copy.powerLimitDescription}
    keys={["ratedPower", "tripDelay", "overcurrent", "overcurrentDelay"]}
    bindings={bindings.powerLimit}
    specs={{
    ratedPower: deviceSettingNumber(3, 450),
    tripDelay: deviceSettingNumber(0, 300),
    overcurrent: deviceSettingChoice(0, 1),
    overcurrentDelay: deviceSettingNumber(0.3, 600, 1),
    }}
    labels={labels}
    locale={locale}
    canWrite={canWrite && connected}
    optionLabel={(key, value) => (key === "overcurrent" ? onOffLabel(value) : null)}
    >
    {(section) => (
    <>
    {section.number("ratedPower")}
    {section.number("tripDelay", { hint: copy.tripDelayHint })}
    {section.switched("overcurrent", { title: copy.overcurrent, options: onOff }, () =>
    section.number("overcurrentDelay"),
    )}
    </>
    )}
    </DeviceSettingsSection>
  3. Build every row while the children function runs, by calling the section’s row helpers and keep there or in plain helper functions. Do not render components that build rows later: the section resets the edits of rows it did not see, so their drafts are lost.

  4. For rules between settings, such as a lower limit below an upper one, pass validate. Return messages only for settings the layout shows.

  5. When the drafts depend on another value that is being read, such as a mode, pass pendingRead.

  6. When a helper proposes drafts with setDraft, offer it only while editable is true.

  7. When a write changes other settings on the device, such as a mode that resets them, read those settings again in onWritten.

  8. When the device needs its writes in order, pass a plan. Give each step that writes none of the changes, such as an unlock or a save to device memory, a label:

    plan={(changes) => [
    { label: copy.unlock, items: [{ paramId: bindings.password, value: password }] },
    ...defaultDeviceSettingsWritePlan(changes),
    { label: copy.saveToMemory, items: [{ paramId: bindings.command, value: SAVE_COMMAND }] }, // from the device manual
    ]}
  9. When the device needs a password, pass unlock; see Ask for a device password.

  10. To say how to unlock a device that acknowledged a write but did not keep it, set notKeptMessage. Use onVerified for follow-ups, such as a banner that asks for a restart.

  11. Put the sections in a DeviceSettingsPage inside an @container, with an intro and onReadAgain.

  12. Next to the settings, state what the drafts do with DeviceSettingOutcome. For a gauge, read the values with useDeviceReadings(parameterIds) and pass its staleSince to the gauge.

  1. Add a DeviceCommandButton with a label, the locale, and steps.
  2. To explain the command in the confirmation, pass children. To mask a password in the list of steps, pass secretParameterIds.
  3. Offer the command only while the device will act on it. Otherwise pass disabled and keep the button mounted, so a command already being sent still reports its result.
  1. Add DeviceRelayTest with the relays, the remote setting that hands the relays over, a title, a description, the device’s warning, and a storageKey that is unique per dashboard and workspace.
  2. Poll the remote setting and every relay’s state and command register while the test view is open.
  3. When DevicePresetLayout shows a page-wide remote-control notice, hide it while useDeviceRelayTestActive(storageKey) is true, so it does not cover the dashboard’s own test.
  1. Bind the room’s parameters in configuration validated by coldRoomBindingsType.

  2. Poll them and show the card:

    const { fastIds, slowIds } = coldRoomParameterIds(bindings);
    useDevicePresetValues({ fastIds, slowIds, live });
    return <ColdRoomCard name="Freezer room 2" bindings={bindings} locale={props.locale} />;

    Pass the dashboard’s pause state as live, or true when the dashboard has no pause control.

  3. For a controller with an unlock or a command timer, list that write as the first step of each command.

  4. To lay a controller out yourself, such as a row per unit, use the card’s parts: coldRoomStatus, coldRoomStatusLabel, coldRoomActiveAlarms, coldRoomAlarmLimitsFromStates, and ColdRoomCommands.

The assistant reads what an open dashboard shows through its page summary. To let it answer about the device from every page:

  1. List the device’s fault flags as SiteAlarmBindings: a condition, an equipment name, a name, and a severity.
  2. Call usePublishDashboardSummary(getSummary), and build a site summary in getSummary with buildSiteSummary.
  3. Get a reader from useReadParameterValuesOnce(), and read the flags with it in getSummary, so pages that do not poll them can answer too.
  4. Pass the flags as the alarms of evaluateSiteStatus for the status, and to activeSiteAlarms for the active alarms.

The summary contract is in Page summary.

  1. The components bring their generic editor and command copy from the host catalogs (device_preset_* and cold_room_* keys). To use the same texts in your own controls, read them with t from @overvis/hmi-workspace-ui/i18n.
  2. Keep device names, reading labels, and mode names in the dashboard’s own typed catalogs; see Localize a dashboard.