使用ogamma Visual Logger for OPC和InfluxDB存储、处理和可视化数据

导航到

本文由One-Way Automation软件架构师Ravil Nugmanov撰写,One-Way Automation是一家位于加拿大埃德蒙顿的初创公司。

本文描述了一个端到端解决方案,该方案使用开源组件InfluxDB和Grafana以及ogamma Visual Logger for OPC,以收集工业过程控制数据,以流式模式分析数据,并在仪表板上进行可视化。

问题

对于此演示,我们使用一个假设的工业泵,该泵通过OPC UA服务器发布以下值

  • 输入压力
  • 输出压力
  • 温度
  • 电源状态

在仪表板上,我们希望可视化以下信息

  • 这些变量的当前值
  • 图表中的历史值
  • 计算输入和输出压力平均值的差异,并在仪表板上显示结果
  • 定期检查从上述数据中计算出的压力差异,如果超出期望范围,则生成通知,并在仪表板上显示。

解决方案

以下是此问题的解决方案图

ogamma opc influxdb

以下章节将详细说明所用组件及其交互方式。

OPC UA 数据源

作为为监测的泵提供值的数据库,我们使用了Prosys OPC UA 模拟服务器。与其他可用的模拟服务器不同,您可以根据特定需求构建自定义的 OPC UA 地址空间,并且可以根据选定的模式(如随机、正弦、锯齿等)自动生成变量的值。

时间序列数据库和流分析引擎

作为时间序列数据库,InfluxDB 被选择是因为它可以以高度有效的方式存储数据,并且支持实时流分析。您可以使用满足您要求的Flux 脚本分析数据,并即时提供结果。

将 OPC UA 服务器中的数据移动到 InfluxDB

为了从 OPC UA 服务器收集数据并将其推送到InfluxDB 时间序列数据库,我们使用了 ogamma Visual Logger for OPC。它可以部署在 Windows、Linux 或 Docker 上,具有基于 Web 的配置图形用户界面,性能高,并且不占用太多硬件资源(用 C++ 编写)。

仪表板中信息的可视化

对于这个演示,使用了另一个开源项目 Grafana。或者,您也可以在 InfluxDB 中构建仪表板。

最终结果:仪表板截图。

最终结果:屏幕录制。

opc ogamma dashboard screen recording

技术细节

配置 Prosys OPC UA 模拟服务器

在 Windows 虚拟机上安装了 Prosys OPC UA 模拟服务器的一个实例。在“对象”文件夹下创建了对象和变量

prosys opc-ua simulation server

从 OPC UA 客户端的角度来看,地址空间看起来是这样的

 opc ua client

变量配置设置截图如下

opc configuration settings

配置 ogamma Visual Logger for OPC 以安全模式连接到服务器

首先,应在地址空间面板中创建一个新的 OPC UA 服务器节点。注意,安全模式设置为签名并加密。在服务器端配置信任将需要一些额外的步骤。

configuring ogamma visual logger

添加 OPC UA 服务器节点后,初始尝试连接将会失败。在服务器端,ogamma Visual Logger 的 OPC UA 应用程序实例证书将被保存在被拒绝的证书文件夹中。从 Prosys OPC UA 模拟服务器 GUI 中,需要将其标记为受信任。这可以在切换到 专家模式(菜单 选项 / 切换到专家模式)后通过 证书 标签页完成

仅仅信任 ogamma Visual Logger 实例证书是不够的。您还需要

  • 下载其 CA 证书(通过菜单设置 / 下载证书 / CA 证书)并将其保存在服务器端的文件夹 C:\Users\Administrator\.prosysopc\prosys-opc-ua-simulation-server\PKI\CA\certs 中,
  • 下载 CRL(通过菜单设置 / 下载证书 / CA CRL)并将其保存在服务器端的文件夹 C:\Users\Administrator\.prosysopc\prosys-opc-ua-simulation-server\PKI\CA\crl 中。

注意:证书实际所在的文件夹在不同的安装中可能会有所不同。因此,请使用Prosys OPC UA模拟服务器GUI打开文件夹,通过菜单证书/ 在文件资源管理器中打开

ogamma visual logger certificate

当证书信任配置正确时,ogamma Visual Logger for OPC应该能够连接到服务器。要验证这一点,请尝试通过在地址空间面板中展开节点来浏览它。

配置ogamma Visual Logger for OPC以记录所需的变量

从地址空间面板选择节点,通过单击日志按钮将它们添加到日志变量表中。如果一切正常,状态列中应显示带勾选标记的图标。

visual logger for opc

配置ogamma Visual Logger for OPC以连接到InfluxDB实例

首先,在时间序列数据库列表中添加一条新记录(菜单 设置/时间序列数据库)。将字段 类型 的值设置为 InfluxDB 2.0,并修改字段主机、端口、使用安全模式和JSON。在最后一个字段(JSON)中,将“测量”选项设置为“[TN]”,并确保选项 组织令牌 设置正确。

opc time series database

visual logger for opc json editor

通过单击 测试连接 按钮验证连接设置是否正确。现在实时数据值将被导入InfluxDB数据库。

以流模式分析变量值并生成通知

对于流分析,使用InfluxDB任务功能。创建此功能通过编写Flux脚本来计算每5秒输入压力和输出压力及其差的平均值。然后根据此差的值生成通知消息。如果差值低于指定的阈值,则消息级别设置为关键,否则设置为警告、信息或正常,具体取决于值。然后通知写入特殊系统桶 _monitoring,其中 _measurement 设置为statuses。

stream analysis influxdb tasks

以下是完整的Flux脚本代码

import "influxdata/influxdb/monitor"

option task = {name: "Check Pump Pressure", every: 5s, offset: 1s}

currentTime = now()

join(tables: {ip: from(bucket: "ogamma")
	|> range(start: -task.every)
	|> filter(fn: (r) =>
		(r._measurement == "InputPressure" and r.unit == "Pump" and r._field == "v"))
	|> drop(columns: ["_source_timestamp"])
	|> mean(column: "_value")
	|> map(fn: (r) =>
		({
			_time: currentTime,
			_value: r._value,
			unit: r.unit,
			_measurement: "OutputPressure",
		})), op: from(bucket: "ogamma")
	|> range(start: -task.every)
	|> filter(fn: (r) =>
		(r._measurement == "OutputPressure" and r.unit == "Pump" and r._field == "v"))
	|> drop(columns: ["_source_timestamp"])
	|> mean(column: "_value")
	|> map(fn: (r) =>
		({
			_time: currentTime,
			_value: r._value,
			unit: r.unit,
			_measurement: "OutputPressure",
		}))}, on: ["_time", "_measurement"])
	|> map(fn: (r) =>
		({
			_time: r._time,
			_pd: r._value_op - r._value_ip,
			unit: r.unit_op,
			_measurement: "OutputPressure",
		}))
	|> monitor.check(
		crit: (r) =>
			(r._pd < 10.0),
		warn: (r) =>
			(r._pd < 15.0),
		info: (r) =>
			(r._pd < 25.0),
		ok: (r) =>
			(r._pd >= 25.0),
		messageFn: (r) =>
			(if r._pd < 10.0 then "Critical alert!! error: Pressure difference is too low: ${string(v: r._pd)}!" else if r._pd < 15.0 then "Warning! Pressure difference is low: ${string(v: r._pd)}!" else if r._pd < 25.0 then "Pressure difference is: ${string(v: r._pd)}!" else "ok"),
		data: {
			_check_name: "Pressure difference check",
			_check_id: "pres_diff",
			_type: "threshold",
			tags: {unit: "Pump"},
			_measurement: "statuses",
		},
	)

在Grafana中可视化实时和流处理数据

Grafana附带一个功能丰富的InfluxDB数据源插件。该插件包括自定义查询编辑器和支持注释和查询模板。要将InfluxDB添加到Grafana中的数据源

  • 通过单击顶部标题中的Grafana图标打开侧菜单
  • 在侧菜单下的仪表板链接下,您应该找到一个名为数据源的超链接
  • 单击顶部标题中的 + 添加数据源按钮
  • 从下拉菜单中选择InfluxDB
  • 确保您从查询语言列表中选择Flux

每个面板使用Flux脚本从InfluxDB查询数据。以下是每个面板及其相应的Flux脚本代码的描述。

状态

此面板显示泵的当前状态,基于布尔类型变量Power的值。

from(bucket: "ogamma")
  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)
  |> filter(fn: (r) =>
    r._measurement == "Power" and
    r._field == "v"
  )
  |> last()
>

输入压力

在此面板中,显示输入压力变量的当前值。

from(bucket: "ogamma")
  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)
  |> filter(fn: (r) =>
    r._measurement == "InputPressure" and
    r._field == "v"
)

输出压力

在此面板中,显示输出压力变量的当前值。

from(bucket: "ogamma")
  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)
  |> filter(fn: (r) =>
    r._measurement == "OutputPressure" and
    r._field == "v"
)

相对压力

在此面板中,显示计算输出和输入压力之间的差的当前值。请注意,对于每个输入和输出压力变量,首先计算平均值,因此差值不等于当前值之间的差。

from(bucket: "_monitoring")
  |> range(start: -10s, stop:now())
  |> filter(fn: (r) =>
    r._measurement == "statuses" and
    r.unit == "Pump"
  )
  |> drop (columns:["_source_timestamp", "_check_id", "_check_name", "_start", "_stop"])

泵:输入和输出压力

在此面板中,显示最新显示间隔内压力变量的历史值。

from(bucket: "ogamma")
  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)
  |> filter(fn: (r) =>
    r._measurement == "InputPressure" and
    r._field == "v"
)

泵通知

在本面板中,显示由流值处理生成的通知。

from(bucket: "_monitoring")
  |> range(start: v.timeRangeStart, stop:v.timeRangeStop)
  |> filter(fn: (r) =>
    r._measurement == "statuses" and
    r.unit == "Pump"
  )
  |> drop(columns: ["_source_timestamp"])

温度

在本面板中,显示温度变量的历史值。

from(bucket: "ogamma") 
  |> range(start: v.timeRangeStart, stop:v.timeRangeStop) 
  |> filter(fn: (r) => 
    r._measurement == "Temperature" and 
    r._field == "v" 
  )

最终结果

最后,我们在Grafana中得到了这个运行的仪表板!

grafana pump monitoring influxdb