Tutorial: Build a Dashboard
Build a line-overview screen: live values, state-coloured equipment, a trend, an alarm banner and drill-down to detail.
You will need: tags with live data (Connect a device) and history enabled on at least one analogue tag. Time: ~30 minutes.
Step 1 — Create the view
Designer → New view.
| Field | Value |
|---|---|
| Name | line1-overview |
| Layout mode | Flex |
Flex because a dashboard should survive being opened on a display size you did not anticipate. Use coordinate for a mimic where position carries meaning — that is a different screen.
Step 2 — Add the alarm banner
Drag an AlarmBell into the top-right corner. It needs no binding — it reads the alarm system directly.
| Property | Value |
|---|---|
countMode | unacked |
colorByPriority | on |
pulseOnNew | on |
Counting unacknowledged rather than all active means the badge reflects work outstanding, not just conditions present.
Step 3 — Add a KPI row
Drop a FlexContainer across the top and put three Text widgets inside it.
Bind each to a tag. On the speed display, add a format transform (#,##0) — or better, set a
format string on the tag so every screen inherits it.
Step 4 — Add a gauge with state colour
Drag a Gauge and bind:
| Property | Binding |
|---|---|
value | tag Site1/Line1/Filler/Motor1/Speed |
min / max | 0 / 3000 |
fillColor | tag …/Speed → threshold transform |
Threshold bands:
value < 2400 → #16a34a normal
2400 – 2800 → #f59e0b high
value > 2800 → #dc2626 too high
The colour is now doing the reading for the operator. That is the point of a dashboard.
Step 5 — Add a running indicator
Drag an Icon and bind color to …/Running with a map transform:
| Input | Output type | Output |
|---|---|---|
true | color | #16a34a |
false | color | #6b7280 |
| fallback | color | #6b7280 |
A grey icon meaning "stopped" and a grey icon meaning "we have no idea" is the failure operators remember. Add a distinct bad-quality appearance, or a small quality indicator beside it.
Step 6 — Add a trend
Drag an HmiTrendChart below the KPI row.
| Property | Value |
|---|---|
| Tags | …/Speed, …/Current |
| Window | Last 1 hour |
| Aggregation | avg |
The chart reads the historian directly. If it is empty, history is not enabled on those tags. → Historian configuration
Use minmax instead of avg when spikes are the reason you are looking — averaging a 200 ms current
spike into a one-minute bucket erases it.
Step 7 — Add drill-down
Drop a Button labelled "Motor detail" and attach a click event:
navigate → view: "motor-detail"
params: { tagPath: "Site1/Line1/Filler/Motor1" }
Then build motor-detail once, parameterised by tagPath. Every motor on the site uses that
one view.
→ Event actions · Embedded views
Step 8 — Add an operator control
Drag a Slider and bind value to …/SpeedSetpoint. Bound to a writable tag, an input widget
reads and writes it.
Two things to get right:
- Set a write level on the tag. A setpoint that changes production should require at least
Operate, and oftenSupervise. - Confirm consequential writes. Tick Confirm on the Set tag action and give it a message, rather than writing on every drag. Confirmation is an option on the action, not something a script asks for.
Slider.change → setTag("Site1/Line1/Filler/Motor1/SpeedSetpoint", value)
with Confirm ticked: "Set the filler speed?"
If you need to do more than write — validate a range, then write, then say so — use a script
action and raise the toast yourself:
const rpm = Number(context.self.props.value);
if (!Number.isFinite(rpm) || rpm > 3000) {
context.ui.notify({ message: "Speed must be at most 3000 RPM", severity: "error" });
return;
}
await system.tag.write("Site1/Line1/Filler/Motor1/SpeedSetpoint", rpm);
context.ui.notify({ message: "Setpoint applied", severity: "success" });
Step 9 — Publish and check as an operator
Save, then open http://localhost:8182/{project}.
You are seeing what an operator sees. Check it on the actual panel hardware — a screen that is comfortable on a laptop can be unreadable on a 10" panel in a bright room.
Step 10 — Review
- Abnormal state is obvious without reading numbers
- Bad quality looks different from a normal value
- Colour is not the only signal for anything safety-relevant
- Text is legible at the real viewing distance
- Touch targets work with gloves
- Detail views are parameterised, not duplicated
- Writes are confirmed and write-level gated
- The screen opens quickly on the target hardware
Next
| Next | Why |
|---|---|
| Alarm on a tag | Make the banner mean something |
| LiveView authentication | Require an operator login |
| Components | The full widget reference |