工业物联网之从 Modbus 到 Web 数据可视化
2018-08-28 09:59
633 查看
前言
工业物联网是一个范围很大的概念,本文从数据可视化的角度介绍了一个最小化的工业物联网平台,从 Modbus 数据采集到前端数据可视化呈现的基本实现思路。这里面主要涉及基于 Modbus 通讯规约的数据采集、后台实时数据处理、前端实时数据接收、前端实时数据可视化显示。物联网平台架构主要参考了图扑物联工业物联网平台,并从中提取了部分功能进行介绍,前端数据可视化采用的是HT for Web。
由于内容比较多,具体实现上涉及到前端工程师、后台工程师、数据采集工程师等多个开发角色的参与,所以本文重点介绍实现思路和 WebSocket 消息推送的实现,其它环节的具体实现细节作者会在其它文章中进行详细介绍。
一、物联网平台架构
物联网平台主要是B/S模式,图扑物联工业物联网平台采用的是微服务架构,本文主要涉及两个微服务:前置数据采集服务和 Web 实时消息推送服务。
前置数据采集服务主要用于现场设备、仪器、仪表、传感器实时数据的采集,图扑物联工业物联网平台支持MQTT和透传云解析两种方式,透传云解析支持 Modbus 通讯规约。
实时数据采集到平台后,需要推送到浏览器端进行显示,Web 实时消息推送服务采用 Web Socket 进行实时数据推送,可以确保数据的实时性和高效性。
前端可视化技术采用的是HT for Web, HT for Web 是基于HTML5标准的企业应用图形界面一站式解决方案,其包含通用组件、拓扑组件和3D渲染引擎等丰富的图形界面开发类库。虽然 HT for Web 是商业软件但其提供的一站式解决方案可以极大缩短产品开发周期、减少研发成本、补齐我们在 Web 图形界面可视化技术上的短板。
二、Modbus 数据采集
Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准,并且现在是工业电子设备之间常用的连接方式。Modbus比其他通信协议使用的更广泛的主要原因有:
公开发表并且无版权要求
易于部署和维护
对供应商来说,修改移动本地的比特或字节没有很多限制
Modbus允许多个 (大约240个) 设备连接在同一个网络上进行通信,举个例子,一个由测量温度和湿度的装置,并且将结果发送给计算机。在数据采集与监视控制系统(SCADA)中,Modbus通常用来连接监控计算机和远程终端控制系统(RTU)。
目前主流的编辑语言都有 Modbus 开发库,由于 Modbus 相对比较简单,很多企业也选择自行开发实现。Modbus 数据采集属于后台通讯,数据采集到平台后首先会进行数据清理和预处理,过滤掉冗余和无效数据,形成实时数据。平台获取到实时数据后一般会做 3 项工作:
1. 推送到 Web 前端进行显示
2. 存储到时序数据库
3. 判断是否产生告警
三、将实时数据推送到 Web 前端
基于 Web 的实时数据推送需要用到 WebSocket,初学者可以学习阮一峰老师的 [u]WebSocket 教程[/u]。[u][u]图扑物联[/u][/u]的物联网平台基于 WebSocket 封装了一套消息传输协议,类似于一个消息中间件,前端部分可以订阅实时数据。考虑到海量实时数据的推送需求,将实时数据分为平台级、站点级、设备级,前端在订阅实时数据时,可以通过消息主题规则订阅不同级别的数据。平台侧在收到订阅请求时,可以主动推送一次实时数据。这样可以确保数据可视化界面在订阅实时数据成功后,第一时间显示出正确的界面。
下面给出一个简化的 WebSocket 消息协议的客户端代码,大家可以在些基础上进行改造以适合自己的业务场景。
消息主题正则表达式,用来匹配消息主题:
WebSocket 客户端,支持消息主题订阅、取消消息主题订阅、同一个消息主题支持多个订阅者:
用法举例:
四、数据可视化界面实现
基于 HT for Web 可以简单快速地搭建一个符合 HTML5 标准的可视化图形界面,通过 WebSocket 订阅实时数据,然后驱动图形界面的变化。数据驱动图形界面变化的实现方式很多,基本方法是采用数据绑定的方式,具体可以参考 HT for Web 的官方文档。
在后面的文章中,作者会介绍一种基于 HT for Web 实现的业务数据和图形数据分离的数据绑定方法,这也是图扑物联的物联网平台采用的方式。
在线演示地址
工业物联网是一个范围很大的概念,本文从数据可视化的角度介绍了一个最小化的工业物联网平台,从 Modbus 数据采集到前端数据可视化呈现的基本实现思路。这里面主要涉及基于 Modbus 通讯规约的数据采集、后台实时数据处理、前端实时数据接收、前端实时数据可视化显示。物联网平台架构主要参考了图扑物联工业物联网平台,并从中提取了部分功能进行介绍,前端数据可视化采用的是HT for Web。
由于内容比较多,具体实现上涉及到前端工程师、后台工程师、数据采集工程师等多个开发角色的参与,所以本文重点介绍实现思路和 WebSocket 消息推送的实现,其它环节的具体实现细节作者会在其它文章中进行详细介绍。
一、物联网平台架构
物联网平台主要是B/S模式,图扑物联工业物联网平台采用的是微服务架构,本文主要涉及两个微服务:前置数据采集服务和 Web 实时消息推送服务。
前置数据采集服务主要用于现场设备、仪器、仪表、传感器实时数据的采集,图扑物联工业物联网平台支持MQTT和透传云解析两种方式,透传云解析支持 Modbus 通讯规约。
实时数据采集到平台后,需要推送到浏览器端进行显示,Web 实时消息推送服务采用 Web Socket 进行实时数据推送,可以确保数据的实时性和高效性。
前端可视化技术采用的是HT for Web, HT for Web 是基于HTML5标准的企业应用图形界面一站式解决方案,其包含通用组件、拓扑组件和3D渲染引擎等丰富的图形界面开发类库。虽然 HT for Web 是商业软件但其提供的一站式解决方案可以极大缩短产品开发周期、减少研发成本、补齐我们在 Web 图形界面可视化技术上的短板。
二、Modbus 数据采集
Modbus是一种串行通信协议,是Modicon公司(现在的施耐德电气Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准,并且现在是工业电子设备之间常用的连接方式。Modbus比其他通信协议使用的更广泛的主要原因有:
公开发表并且无版权要求
易于部署和维护
对供应商来说,修改移动本地的比特或字节没有很多限制
Modbus允许多个 (大约240个) 设备连接在同一个网络上进行通信,举个例子,一个由测量温度和湿度的装置,并且将结果发送给计算机。在数据采集与监视控制系统(SCADA)中,Modbus通常用来连接监控计算机和远程终端控制系统(RTU)。
目前主流的编辑语言都有 Modbus 开发库,由于 Modbus 相对比较简单,很多企业也选择自行开发实现。Modbus 数据采集属于后台通讯,数据采集到平台后首先会进行数据清理和预处理,过滤掉冗余和无效数据,形成实时数据。平台获取到实时数据后一般会做 3 项工作:
1. 推送到 Web 前端进行显示
2. 存储到时序数据库
3. 判断是否产生告警
三、将实时数据推送到 Web 前端
基于 Web 的实时数据推送需要用到 WebSocket,初学者可以学习阮一峰老师的 [u]WebSocket 教程[/u]。[u][u]图扑物联[/u][/u]的物联网平台基于 WebSocket 封装了一套消息传输协议,类似于一个消息中间件,前端部分可以订阅实时数据。考虑到海量实时数据的推送需求,将实时数据分为平台级、站点级、设备级,前端在订阅实时数据时,可以通过消息主题规则订阅不同级别的数据。平台侧在收到订阅请求时,可以主动推送一次实时数据。这样可以确保数据可视化界面在订阅实时数据成功后,第一时间显示出正确的界面。
下面给出一个简化的 WebSocket 消息协议的客户端代码,大家可以在些基础上进行改造以适合自己的业务场景。
消息主题正则表达式,用来匹配消息主题:
1 const matchWildcard = function(str, rule) { 2 return new RegExp('^' + rule.split('*').join('.*') + '$').test(str) 3 }
WebSocket 客户端,支持消息主题订阅、取消消息主题订阅、同一个消息主题支持多个订阅者:
class WebSocketClient { constructor() { this.ws = null this.opts = { debug: false, autoReconnect: true, reconnectInterval: 10000, subscriber: {}, } this.opened = false } connect() { if (!this.opened) { return } const url = 'ws://www.iotopo.com/msg/v1' console.debug('websocket connect', url) let ws = this.ws = new WebSocket(url) ws.onmessage = event => { if (this.opts.debug) { console.log(event) } let data = JSON.parse(event.data) for (let topic in this.opts.subscriber) { if (matchWildcard(data.topic, topic)) { let listeners = this.opts.subscriber[topic] if (Array.isArray(listeners)) { listeners.forEach(cb => { if (typeof cb === 'function') { cb(data.payload) } }) } } } } ws.onopen = e => { if (this.opts.debug) { console.log(e) } // 执行订阅请求 for (let topic in this.opts.subscriber) { this._sendSubscribe(topic) } if (typeof this.opts.onopen === 'function') { this.opts.onopen(e) } } ws.onclose = e => { if (this.opts.debug) { console.log(e) } if (typeof this.opts.onclose === 'function') { this.opts.onclose(e) } if (this.opened && this.opts.autoReconnect) { setTimeout(() => { this.connect() }, this.opts.reconnectInterval) } } ws.onerror = e => { if (this.opts.debug) { console.log(e) } if (typeof this.opts.onerror === 'function') { this.opts.onerror(e) } } } open(opts) { if (!this.opened) { Object.assign(this.opts, opts || {}) this.opened = true this.connect() } } close() { this.opened = false if (this.ws !== null) { this.ws.close() } this.ws = null } isOpened() { return this.opened } isConnected() { return this.ws !== null } _sendSubscribe(topic) { if (this.ws === null) { return Error('websocet not opened') } if (typeof topic !== 'string') { return Error('topic should be a string value') } if (this.ws.readyState === WebSocket.OPEN) { let msg = { type: 'subscribe', topic: topic, } this.ws.send(JSON.stringify(msg)) } else { return Error('websocet not connected') } } subscribe(topic, cb) { if (this.opts.debug) { console.log('subscribe:', topic) } let listeners = this.opts.subscriber[topic] if (!Array.isArray(listeners)) { listeners = [ cb ] this.opts.subscriber[topic] = listeners } else { listeners.push(cb) } this._sendSubscribe(topic) return { topic, cb } } unsubscribe({topic, cb}) { if (this.opts.debug) { console.log('unsubscribe:', topic) } if (this.ws === null) { return Error('websocet not opened') } if (typeof topic !== 'string') { return Error('topic should be a string value') } let listeners = this.opts.subscriber[topic] if (cb) { if (Array.isArray(listeners)) { let idx = listeners.indexOf(cb) if (idx >= 0) { listeners.splice(idx, 1) } } } else { delete this.opts.subscriber[topic] } if (Array.isArray(listeners) && listeners == 0) { if (this.ws.readyState === WebSocket.OPEN) { let msg = { type: 'unsubscribe', topic: topic, } this.ws.send(JSON.stringify(msg)) } else { return Error('websocet not connected') } } } }
用法举例:
// 初始化客户端 const ws = new WebSocketClient() // 与 WebSocket 服务器建议连接 ws.open({ debug: false }) // 订阅消息 ws.subscribe('/foo/bar/*', function(msg) { console.log('recv ws msg:', msg) })
四、数据可视化界面实现
基于 HT for Web 可以简单快速地搭建一个符合 HTML5 标准的可视化图形界面,通过 WebSocket 订阅实时数据,然后驱动图形界面的变化。数据驱动图形界面变化的实现方式很多,基本方法是采用数据绑定的方式,具体可以参考 HT for Web 的官方文档。
在后面的文章中,作者会介绍一种基于 HT for Web 实现的业务数据和图形数据分离的数据绑定方法,这也是图扑物联的物联网平台采用的方式。
在线演示地址
相关文章推荐
- Web 数据可视化
- web页面上可视化展示JSON数据的方法
- C#工业物联网和集成系统解决方案的技术路线(数据源、数据采集、数据上传与接收、ActiveMQ、Mongodb、WebApi、手机App)
- 工业4.0时代,您需要的是高性价工业物联网智能网关,PLC远程监控,PLC远程维护,系统数据采集,一个都不能少。
- WEB--数据可视化资源
- 一张图解读工业4.0与物联网,云计算和大数据的关系
- 工业大数据漫谈16:物联网(IOT)与工业大数据的关系
- web页面上可视化展示JSON数据的方法
- 数据可视化之从Web收集数据小实例
- MAMP和WAMP搭建Web环境,数据库,数据分布可视化
- 物联网平台设计心得:列表数据可视化
- 结合JQuery Flot组件的工业动态数据Web监控
- 物联网平台设计心得:图表数据可视化
- Webstorm+Webpack+echarts构建个性化定制的数据可视化图表&&两个echarts详细教程(柱状图,南丁格尔图)
- 【工业物联网】Ruff 率先实现 CNC 设备数据采集 加速工厂数字化转型
- 工业大数据漫谈11:工业大数据可视化的难点
- [好书推荐]《WEB+DB PRESS 中文版 01》UI设计+Web支付+数据可视化
- 基于Web的数据可视化的时代
- 浅谈大数据时代下web数据可视化探析
- 浅谈大数据时代web数据可视化探析