仪表板可视化
仪表板可视化
本节介绍如何构建自动投料系统的 Node-RED Dashboard,实时展示液位趋势、投料记录和设备状态。学习完成后,您将能够:
- 创建液位趋势图表
- 显示投料记录和下次投料时间
- 构建设备运行监控面板
- 设计多容器 Dashboard
Dashboard Layout
Section titled “Dashboard Layout”┌──────────────────────────────────────────────────────────────┐│ 🌿 自动投料系统 Dashboard │├──────────────────────────────────────────────────────────────┤│ ││ ┌───────────────┐ ┌───────────────────────────────────┐ ││ │ 容器 A 状态 │ │ 液位趋势 (24h) │ ││ │ ┌─────────┐ │ │ ╭───╮ │ ││ │ │ 33% │ │ │ │███│ │ ││ │ │ █████ │ │ │ ├───┤ │ ││ │ │ █████ │ │ │ │ │ ╭───╮ │ ││ │ │ ████ │ │ │ ╰─╯─╰──╯ ╰──╮ │ ││ │ └─────────┘ │ └───────────────────────────────────┘ ││ │ 距离: 16cm │ ││ └───────────────┘ ┌───────────────────────────────────┐ ││ │ 投料记录 │ ││ ┌───────────────┐ │ 昨天 08:00 ✅ 投料 3s │ ││ │ 下次投料 │ │ 今天 08:00 ✅ 投料 3s │ ││ │ ⏳ 23小时后 │ │ 明天 08:00 ⏳ 等待中 │ ││ └───────────────┘ └───────────────────────────────────┘ ││ ││ ┌───────────────┐ ┌───────────────────────────────────┐ ││ │ 设备状态 │ │ 告警通知 │ ││ │ 🟢 在线 │ │ ℹ️ 容器液位正常 │ ││ │ 上次唤醒: │ │ │ ││ │ 14:30:25 │ │ │ ││ └───────────────┘ └───────────────────────────────────┘ ││ │└──────────────────────────────────────────────────────────────┘Step 1: Install Dashboard
Section titled “Step 1: Install Dashboard”# 通过 Palette 安装 Dashboardnpm install node-red-dashboard
# 或docker exec -it nodered npm install node-red-dashboardStep 2: Create UI Elements
Section titled “Step 2: Create UI Elements”使用 ui_gauge 节点显示当前液位百分比:
[MQTT In: esp32/dosing/info] ──→ [Function: 提取液位] ──→ [ui_gauge] ──→ [ui_text]Function 节点:
// Function: 提取液位数据供 Dashboard 显示var data = msg.payload;
// 更新 Flow Contextflow.set("lastLevel", data.level);flow.set("lastDistance", data.distance);flow.set("lastWakeTime", Date.now());flow.set("bootCount", data.boot);flow.set("totalDosing", data.total_dosing);
// 输出给 ui_gauge (液位百分比 0-100)msg.payload = data.level;return msg;ui_gauge 配置:
| 参数 | 值 |
|---|---|
| Group | Dosing Dashboard |
| Type | Gauge |
| Label | 液位 |
| Value format | {{value}}% |
| Min | 0 |
| Max | 100 |
| Color | Green-Yellow-Red |
液位趋势图 (24h)
Section titled “液位趋势图 (24h)”使用 ui_chart 节点显示历史液位趋势:
[MQTT In: esp32/dosing/info] ──→ [Function: 图表数据] ──→ [ui_chart]Function 节点:
// Function: 构建图表数据 (最近 24 小时)// 从数据库查询历史数据
msg.topic = "SELECT timestamp, level1 FROM level_history " + "WHERE timestamp > UNIX_TIMESTAMP() - 86400 " + "ORDER BY timestamp ASC";
return msg;查询完成后,使用另一个 Function 格式化:
// Function: 格式化图表数据var rows = msg.payload;
if (!rows || rows.length === 0) { msg.payload = []; return msg;}
// 转换为图表格式var chartData = rows.map(function(row) { return { x: new Date(row.timestamp * 1000).toISOString(), y: row.level1 };});
msg.payload = chartData;return msg;ui_chart 配置:
| 参数 | 值 |
|---|---|
| Group | Dosing Dashboard |
| Type | Line Chart |
| Label | 液位趋势 (24h) |
| X Axis | Labels |
| Y Axis | Min: 0, Max: 100 |
| Interval | 1000 (1 秒刷新) |
| Points | 24 (每点 1 小时) |
[MQTT In: esp32/dosing/status] ──→ [Function: 投料日志] ──→ [ui_table]// Function: 更新投料日志var status = msg.payload;
// 获取现有日志var log = flow.get("dosingLog") || [];
// 添加新条目if (status.state === "complete" || status.state === "pumping") { log.unshift({ time: new Date().toLocaleString(), event: status.state === "complete" ? "✅ 投料完成" : "⏳ 投料中", duration: status.state === "complete" ? "3s" : "-", level: flow.get("lastLevel") + "%" });
// 保留最近 20 条 if (log.length > 20) log.pop();
flow.set("dosingLog", log);}
msg.payload = log;return msg;Step 3: Multi-Container Dashboard
Section titled “Step 3: Multi-Container Dashboard”// Function: 多容器 Dashboard 数据聚合
// 容器配置var containers = flow.get("containers") || [ {id: "doser_01", name: "原料 A", height: 24}, {id: "doser_02", name: "原料 B", height: 30}, {id: "doser_03", name: "原料 C", height: 20}];
// 为每个容器获取数据var dashboardData = containers.map(function(c) { var data = flow.get(c.id + "_lastData") || {}; return { name: c.name, level: data.level || 0, distance: data.distance || 0, status: data.state || "unknown", lastWake: flow.get(c.id + "_lastWake") || "-" };});
msg.payload = dashboardData;return msg;Step 4: Dashboard UI Template (Custom)
Section titled “Step 4: Dashboard UI Template (Custom)”对于更复杂的布局,使用 ui_template 节点:
<!-- ui_template: 投料系统概览 --><div class="dosing-dashboard"> <style> .container-card { background: #fff; border-radius: 8px; padding: 15px; margin: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .level-bar { height: 20px; border-radius: 10px; background: linear-gradient(90deg, #dc3545 0%, #ffc107 50%, #28a745 100%); transition: width 1s ease; } .status-online { color: #28a745; } .status-offline { color: #dc3545; } .next-dosing { font-size: 24px; font-weight: bold; color: #007bff; } </style>
<div class="container-card" ng-repeat="c in msg.containers"> <h3>{{c.name}} <span class="status-{{c.status}}">●</span></h3> <div class="level-bar" style="width: {{c.level}}%"></div> <p>液位: {{c.level}}% | 距离: {{c.distance}}cm</p> </div>
<div class="container-card"> <p>下次投料: <span class="next-dosing">{{msg.nextDosing}}</span></p> <p>总投料次数: {{msg.totalDosing}}</p> </div></div>Step 5: Periodic Dashboard Refresh
Section titled “Step 5: Periodic Dashboard Refresh”// Function: 定时刷新 Dashboard 数据// 由 Inject 节点每 5 分钟触发
// 重新查询数据库获取最新趋势msg.topic = "SELECT timestamp, level1 FROM level_history " + "ORDER BY id DESC LIMIT 24";
return msg;Complete Dashboard Tab
Section titled “Complete Dashboard Tab”Dashboard Tab: "自动投料"├── Group: "容器状态"│ ├── ui_gauge: 液位 (%)│ ├── ui_text: 距离 (cm)│ └── ui_text: 设备状态├── Group: "液位趋势"│ ├── ui_chart: 24h 趋势│ └── ui_chart: 周趋势├── Group: "投料控制"│ ├── ui_button: 手动投料│ ├── ui_dropdown: 选择容器│ └── ui_text: 下次投料├── Group: "投料日志"│ └── ui_table: 最近记录└── Group: "设备监控" ├── ui_text: 唤醒计数 ├── ui_text: 总投料次数 └── ui_text: 最近唤醒时间# 1. 打开 Dashboard# 2. 模拟传感器数据mosquitto_pub -t "esp32/dosing/info" \ -m '{"distance":16,"level":33,"boot":5,"total_dosing":3}'
# 3. 验证 Dashboard 更新# - 液位仪表显示 33%# - 距离显示 16cm# - 设备状态显示 🟢
# 4. 模拟投料mosquitto_pub -t "esp32/dosing/status" \ -m '{"state":"complete"}'# - 日志表格出现新条目Common Customer Questions
Section titled “Common Customer Questions”Q1: Dashboard 可以导出为报告吗?
Section titled “Q1: Dashboard 可以导出为报告吗?”可以。使用 Node-RED 的 ui_template 加上 PDF 导出功能,或使用 Grafana 作为替代方案(支持导出 PDF/CSV)。
Q2: 如何实现手机端查看?
Section titled “Q2: 如何实现手机端查看?”Dashboard 自带响应式设计,手机浏览器直接访问即可。也可以通过 Telegram Bot 发送每日液位摘要。
Q3: 支持实时刷新吗?
Section titled “Q3: 支持实时刷新吗?”MQTT 消息触发更新是即时的。图表数据需要按需刷新(推荐 5-15 分钟/次),避免频繁查询数据库。
✅ 推荐做法:
- 使用 Flow Context 缓存最新数据,减少数据库查询
- 图表数据使用定时刷新,避免每次 MQTT 消息都查库
- Dashboard 分组按功能划分清晰
- 添加手动投料按钮用于测试和应急
- 移动端优先设计,确保手机查看体验
❌ 避免做法:
- Dashboard 上直接显示原始 JSON 数据
- 图表查询频率过高(<1 分钟)导致数据库压力
- 未处理传感器故障时的数据显示(显示 ”-” 而非错误值)
- 忽略 Dashboard 权限控制(生产环境需加认证)
Summary
Section titled “Summary”- UI 元素: Gauge (液位), Chart (趋势), Table (日志), Button (控制)
- 数据流: MQTT → Function → Dashboard UI 节点
- 缓存策略: Flow Context 缓存最新值,定时刷新历史趋势
- 多容器: 通过设备 ID 区分数据源
- Dashboard Tab: 容器状态 → 趋势 → 日志 → 监控