Node-RED Dashboard State Trail Chart
node-red-contrib-ui-state-trail is a Node-RED dashboard UI node that renders a Gantt-type chart to visualize the historical changes of a state over a configurable time period. It is designed for displaying single-line state timelines, such as the operational status (on/off, running/stopped) of a device or process. The current stable version is 1.0.2. As a Node-RED contrib node, it typically receives updates on an as-needed basis rather than a strict release cadence, focusing on stability and new features. Key differentiators include its ability to accept both simple and timestamped historical data, customizable legend display (showing all states, current states, or latest state), state aggregation for performance, and optional persistent data storage when Node-RED's context storage is properly configured. It supports string, number, and boolean state types, which are treated distinctly.
Common errors
-
Chart data disappears after Node-RED restart or full redeploy.
cause Persistent context storage is not enabled or configured incorrectly.fixGo to Node-RED `settings.js`, configure a persistent context storage (e.g., `localfilesystem`), and ensure the 'Data Storage' checkbox is selected in the State Trail node's properties. -
Chart performance is slow, or the dashboard becomes unresponsive when viewing the State Trail.
cause Too much data is being fed to the node over a long configured period, overwhelming rendering capabilities.fixReduce the `Period` setting in the node's configuration, lower the frequency of input messages, or ensure the 'Combine similar states' option is checked to reduce data points. -
The chart legend or node label is not displayed on the Node-RED dashboard.
cause The UI widget's height is set too low in the dashboard layout.fixEdit the Node-RED Dashboard layout, find the State Trail node, and increase its 'Height' property to at least 2 units. -
States like 'true' and "true" are shown as different entries on the chart or in the legend.
cause The node differentiates between data types (boolean, string, number).fixStandardize the data type for your states (e.g., always send `true` boolean or always send `"true"` string) or configure both `true` and `"true"` as distinct states with appropriate labels in the node's configuration.
Warnings
- gotcha Performance can significantly degrade with long periods and high input rates, especially on lower-end hardware, due to the volume of data needing to be rendered. Use the 'combine similar states' option to mitigate this.
- gotcha Chart data will be lost on Node-RED redeploy, restart, or system reboot unless persistent context storage is explicitly configured in Node-RED's `settings.js` file AND the 'Data Storage' option is enabled in the node's configuration.
- gotcha Boolean states (`true`, `false`) and string states (`"true"`, `"false"`) are treated as distinct values. Mixing types for what appears to be the 'same' state will result in separate entries on the chart and in the legend.
- gotcha The legend and labels configured for the widget will not be visible on the dashboard if the widget's height is set to less than 2 units in the Node-RED Dashboard layout.
- gotcha When feeding an array of historical data (`msg.payload = [...]`), the previous set of data in the chart is cleared and replaced by the new array. This is intentional for batch updates but can be unexpected if continuous appending is desired.
Install
-
npm install node-red-contrib-ui-state-trail -
yarn add node-red-contrib-ui-state-trail -
pnpm add node-red-contrib-ui-state-trail
Imports
- msg.payload (simple state)
msg.payload = { value: true };msg.payload = true; // or 'running', 1
- msg.payload (historical state)
msg.payload = { value: 'on', time: Date.now() };msg.payload = { state: 'on', timestamp: Date.now() }; - msg.control (period override)
msg.control = { period_ms: 300000 };msg.control = { period: 300000 }; // 5 minutes
Quickstart
[
{
"id": "inject_current_state",
"type": "inject",
"name": "Send 'running'",
"topic": "",
"payload": "running",
"payloadType": "str",
"repeat": "5",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 160,
"y": 100,
"wires": [
["state_trail_node"]
]
},
{
"id": "inject_historical_data",
"type": "inject",
"name": "Send Historical Data",
"topic": "",
"payload": "[
{state: \"stopped\", timestamp: Date.now() - 3600000},
{state: \"running\", timestamp: Date.now() - 1800000},
{state: \"error\", timestamp: Date.now() - 600000}
]",
"payloadType": "json_ata",
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": 1,
"x": 190,
"y": 160,
"wires": [
["state_trail_node"]
]
},
{
"id": "inject_control_period",
"type": "inject",
"name": "Set Period to 10 min",
"topic": "",
"payload": "{\"period\":600000}",
"payloadType": "json",
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": 2,
"x": 190,
"y": 220,
"wires": [
["state_trail_node"]
]
},
{
"id": "state_trail_node",
"type": "ui_state_trail",
"z": "flow_id", // Replace with your flow ID
"group": "dashboard_group", // Replace with your dashboard group ID
"name": "My State Trail",
"label": "Process State",
"order": 0,
"width": 0,
"height": 2,
"period": 3600000, // Default to 1 hour
"period_unit": "hour",
"combine": true,
"states": [
{ "state": "running", "label": "Running" },
{ "state": "stopped", "label": "Stopped" },
{ "state": "error", "label": "Error" },
{ "state": true, "label": "Active" },
{ "state": false, "label": "Inactive" }
],
"legend": 0,
"ticks": 6,
"x": 450,
"y": 100,
"wires": []
}
]