IOTOS物联中台Modbus_Tcp驱动对接Wheelers控制器设备
目录
前言
驱动目的
适用范围
使用示例
驱动源码
驱动解析
前言
Modbus协议是一种已广泛应用于当今工业控制领域的通用通讯协议。通过此协议,控制器相互之间、或控制器经由网络(如以太网)可以和其它设备之间进行通信。Modbus协议使用的是主从通讯技术,即由主设备主动查询和操作从设备。一般将主控设备方所使用的协议称为Modbus Master,从设备方使用的协议称为Modbus Slave。典型的主设备包括工控机和工业控制器等;典型的从设备如PLC可编程控制器等。
Modbus TCP/IP协议,去掉了Modbus协议本身的CRC校验,增加了MBAP 报文头。TCP/IP上的Modbus的请求/响应。
驱动目的
将该类型的控制器的相关监测数据对接至IOTOS的线上中台
适用范围
Wheelers的控制器
使用示例
- 连接设备
将设备的电源插上,听到嘀嘀嘀的声音后表面设备正常启动,然后将网线一端插入到设备的网口,一端插入到电脑的网口
- 访问设备
打开电脑的更改适配器选项
找到刚才插入的网口的网卡 ,右键属性,更改其IP地址,使得与控制器在一个网段且IP不一样。
这里该控制器的IP为192.168.11.111,所以将自己电脑的IP改为11网段的即可
更改完IP后打开cmd,ping控制器的IP如果可以ping则说明 可以访问到控制器
- 中台操作
这里只说明了大致的操作流程,具体细节可以参考中台中台文档手册
首先在IOTOS中台创建网关,再打开的界面填写名称后点击确认即可创建成功
网关创建成功后去[我的模板]进行模板的创建
模板的内容如下:
创建完成后再去创建设备实例
选择刚刚创建的网关和模板,点击确认即可创建成功
最后去创建数据点,删除自带的四个数据点然后点击创建数据点,填写名称,选择类型。
然后点击高级配置,填写需要的参数
这样批量读取后,读取几个后面的数据点就要创建几个。
然后其他十二个的配置为
也可以进行单个量的读取,修改其配置即可
- SDK运行驱动
配置完后,在SDK目录下的_driver路径下新建一个名为dr_modbus_tcp的py文件,若路径下已有则不用再创建,其文件内容如下一节源码内容,然后在_example创建一个运行脚本.bat文件,内容如下:
创建完成后双击运行即可看到数据已经上报
至此控制器已经对接完成
驱动源码
# -*- coding:utf-8 -*-
# author : jiji time 12/10/2021
# Modbus tcp server
import sys
import modbus_tk.modbus_tcp as modbus_tcp
from modbus_tk.exceptions import ModbusInvalidResponseError
reload(sys)
sys.setdefaultencoding('utf8')sys.path.append("..")
from driver import *# 补码转为负数
def Complement2Negative(int_data):data = '0b'bin_data = bin(int_data).split('0b')[1]print bin(int_data)if len(bin_data) < 16:return int_dataelse:for i in bin_data:if i == '1':data += '0'if i == '0':data += '1'return (int(data,2)+1)*-1class ModbusTCPDriver(IOTOSDriverI):#1、通信初始化def InitComm(self,attrs):self._HOST = self.sysAttrs['config']['param']['HOST']self._PORT = self.sysAttrs['config']['param']['PORT']self._master = modbus_tcp.TcpMaster(host=self._HOST, port=self._PORT)self._master.set_timeout(5.0)self.online(True)self.setPauseCollect(False)self.setCollectingOneCircle(False)# #2、采集引擎回调,可也可以开启,也可以直接注释掉(对于主动上报,不存在遍历采集的情况)def Collecting(self, dataId):try:cfgtmp = self.data2attrs[dataId]['config']# 过滤非modbus tcp配置的点if not cfgtmp.has_key('param') or not cfgtmp.has_key('proxy'):return ()# 当是新一组功能号时;当没有proxy.pointer,或者有,但是值为null时,就进行采集!否则(有pointer且值不为null,表明设置了采集代理,那么自己自然就被略过了,因为被代理了)当前数据点遍历轮询会被略过!if 'pointer' not in cfgtmp['proxy'] or cfgtmp['proxy']['pointer'] == None or cfgtmp['proxy']['pointer'] == '':# 某些过滤掉不采集,因为有的地址的设备不在线,只要在proxy下面配置disabled:true,这样就不会轮训到它!if 'disabled' in cfgtmp['proxy'] and cfgtmp['proxy']['disabled'] == True:return ()else:self.warn(self.name(dataId))# 过滤非modbus rtu配置的点if not cfgtmp['param'].has_key('funid'):return ()# 功能码funid = cfgtmp['param']['funid']# 设备地址devid = cfgtmp['param']['devid']# 寄存器地址regad = cfgtmp['param']['regad']# 格式format = cfgtmp['param']['format']# 长度quantity = re.findall(r"\d+\.?\d*", format)if len(quantity):quantity = int(quantity[0])else:quantity = 1if format.lower().find('i') != -1: # I、i类型数据为4个字节,所以n个数据,就是4n字节,除一般应对modbus标准协议的2字节一个数据的个数单位!quantity *= 4 / 2elif format.lower().find('h') != -1:quantity *= 2 / 2elif format.lower().find('b') != -1:quantity *= 1 / 2elif format.find('d') != -1:quantity *= 8 / 2elif format.find('f') != -1:quantity *= 4 / 2elif format.find('?') != -1: # 对于功能号1、2的开关量读,开关个数,对于这种bool开关型,个数就不是返回字节数的两倍了!返回的字节个数是动态的,要字节数对应的位数总和,能覆盖传入的个数数值!quantity *= 1format = '' # 实践发现,对于bool开关型,传入开关量个数就行,format保留为空!如果format设置为 "?"或"8?"、">?"等,都会解析不正确!!self.debug('>>>>>>' + '(PORT-' + str(self._PORT) + ')' + str(devid) + ' ' + str(funid) + ' ' + str(regad) + ' ' + str(quantity) + ' ' + str(format))rtu_ret = self._master.execute(devid, funid, regad, quantity, data_format=format)self.debug(rtu_ret)# 私有modbus解析if cfgtmp['param'].has_key('private'):# 温湿度传感器if cfgtmp['param']['private'] == 'Temp&Hum':data_list = []for i in rtu_ret:data_list.append(Complement2Negative(i)*0.1)rtu_ret = tuple(data_list)if cfgtmp['param']['private'] == 'time':# wheelers表的时间的解析rtu_ret = str(rtu_ret[0]) + "年" + str(rtu_ret[1]) + "月" + str(rtu_ret[3]) + "日" + str(rtu_ret[4]) + "时" + str(rtu_ret[5]) + "分" + str(rtu_ret[6]) +"秒"return (rtu_ret,)return rtu_retexcept ModbusInvalidResponseError, e:self.error(u'MODBUS响应超时, ' + e.message)return Noneexcept Exception, e:traceback.print_exc(e.message)self.error(u'采集解析参数错误:' + e.message)return Nonedef Event_setData(self, dataId, value):# self.setValue(self.name(dataId),value)return json.dumps({'code': 0, 'msg': '', 'data': ''})
驱动解析
- 导入相关的包,包括Modbus Tcp连接所需要的包和iotos运行驱动的依赖包
# -*- coding:utf-8 -*-
# Modbus tcp server
import sys
import modbus_tk.modbus_tcp as modbus_tcp
from modbus_tk.exceptions import ModbusInvalidResponseError
reload(sys)
sys.setdefaultencoding('utf8')sys.path.append("..")
from driver import *
- 通讯初始化,定义驱动需要运行的类并将其初始化,获取中台配置的IP和端口并进行TCP的连接
class ModbusTCPDriver(IOTOSDriverI):#1、通信初始化def InitComm(self,attrs):self._HOST = self.sysAttrs['config']['param']['HOST']self._PORT = self.sysAttrs['config']['param']['PORT']self._master = modbus_tcp.TcpMaster(host=self._HOST, port=self._PORT)self._master.set_timeout(5.0)self.online(True)self.setPauseCollect(False)self.setCollectingOneCircle(False)
- 编写采集函数。获取中台数据点的配置,然后通过已连接的Tcp用数据点里面的配置向控制器发生命令,得到返回值后进行数据点的赋值
# #2、采集引擎回调,可也可以开启,也可以直接注释掉(对于主动上报,不存在遍历采集的情况)def Collecting(self, dataId):try:cfgtmp = self.data2attrs[dataId]['config']# 过滤非modbus tcp配置的点if not cfgtmp.has_key('param') or not cfgtmp.has_key('proxy'):return ()# 当是新一组功能号时;当没有proxy.pointer,或者有,但是值为null时,就进行采集!否则(有pointer且值不为null,表明设置了采集代理,那么自己自然就被略过了,因为被代理了)当前数据点遍历轮询会被略过!if 'pointer' not in cfgtmp['proxy'] or cfgtmp['proxy']['pointer'] == None or cfgtmp['proxy']['pointer'] == '':# 某些过滤掉不采集,因为有的地址的设备不在线,只要在proxy下面配置disabled:true,这样就不会轮训到它!if 'disabled' in cfgtmp['proxy'] and cfgtmp['proxy']['disabled'] == True:return ()else:self.warn(self.name(dataId))# 过滤非modbus rtu配置的点if not cfgtmp['param'].has_key('funid'):return ()# 功能码funid = cfgtmp['param']['funid']# 设备地址devid = cfgtmp['param']['devid']# 寄存器地址regad = cfgtmp['param']['regad']# 格式format = cfgtmp['param']['format']# 长度quantity = re.findall(r"\d+\.?\d*", format)if len(quantity):quantity = int(quantity[0])else:quantity = 1if format.lower().find('i') != -1: # I、i类型数据为4个字节,所以n个数据,就是4n字节,除一般应对modbus标准协议的2字节一个数据的个数单位!quantity *= 4 / 2elif format.lower().find('h') != -1:quantity *= 2 / 2elif format.lower().find('b') != -1:quantity *= 1 / 2elif format.find('d') != -1:quantity *= 8 / 2elif format.find('f') != -1:quantity *= 4 / 2elif format.find('?') != -1: # 对于功能号1、2的开关量读,开关个数,对于这种bool开关型,个数就不是返回字节数的两倍了!返回的字节个数是动态的,要字节数对应的位数总和,能覆盖传入的个数数值!quantity *= 1format = '' # 实践发现,对于bool开关型,传入开关量个数就行,format保留为空!如果format设置为 "?"或"8?"、">?"等,都会解析不正确!!self.debug('>>>>>>' + '(PORT-' + str(self._PORT) + ')' + str(devid) + ' ' + str(funid) + ' ' + str(regad) + ' ' + str(quantity) + ' ' + str(format))rtu_ret = self._master.execute(devid, funid, regad, quantity, data_format=format)self.debug(rtu_ret)# 私有modbus解析if cfgtmp['param'].has_key('private'):# 温湿度传感器if cfgtmp['param']['private'] == 'Temp&Hum':data_list = []for i in rtu_ret:data_list.append(Complement2Negative(i)*0.1)rtu_ret = tuple(data_list)if cfgtmp['param']['private'] == 'time':# wheelers表的时间的解析rtu_ret = str(rtu_ret[0]) + "年" + str(rtu_ret[1]) + "月" + str(rtu_ret[3]) + "日" + str(rtu_ret[4]) + "时" + str(rtu_ret[5]) + "分" + str(rtu_ret[6]) +"秒"return (rtu_ret,)return rtu_retexcept ModbusInvalidResponseError, e:self.error(u'MODBUS响应超时, ' + e.message)return Noneexcept Exception, e:traceback.print_exc(e.message)self.error(u'采集解析参数错误:' + e.message)return None
- 编写下发函数。也可以不定义,定义后可以用于中台数据点的下发
def Event_setData(self, dataId, value):# self.setValue(self.name(dataId),value)return json.dumps({'code': 0, 'msg': '', 'data': ''})
IOTOS物联中台Modbus_Tcp驱动对接Wheelers控制器设备相关推荐
- IOTOS物联中台modbus驱动对接雅达电表设备
本文章为原创,转载请注明出处! 登录平台:IOTOS®爱投斯物联中台 账号:iotos_test 密码:iotos123 代码地址:IOTOSDK-Python: IOTOS Python版本S ...
- IOTOS物联中台modbus驱动对接科士达精密空调设备
本文章为原创,转载请注明出处! 登录平台:IOTOS®爱投斯物联中台 账号:iotos_test 密码:iotos123 代码地址:IOTOSDK-Python: IOTOS Python版本S ...
- IOTOS物联中台开发驱动支持NB-IoT光电感烟火灾探测报警器设备
本文章为原创,转载请注明出处! 登录平台:IOTOS®爱投斯物联中台 账号:iotos_test 密码:iotos123 代码地址:IOTOSDK-Python: IOTOS Python版本S ...
- IOTOS物联中台开发驱动支持中安易科智能门锁API 详解
本文章为原创,转载请注明出处! 登录平台:IOTOS®爱投斯物联中台 账号:iotos_test 密码:iotos123 代码地址:IOTOSDK-Python: IOTOS Python版本S ...
- IOTOS物联中台Bacnet驱动开发实例
本文章为原创,转载请注明出处! 登录平台:IOTOS®爱投斯物联中台 账号:iotos_test 密码:iotos123 代码地址:IOTOSDK-Python: IOTOS Python版本S ...
- IOTOS物联中台非标modbus驱动对接易事特UPS电源设备
本文章为原创,转载请注明出处! 登录平台:IOTOS®爱投斯物联中台 账号:iotos_test 密码:iotos123 代码地址:IOTOSDK-Python: IOTOS Python版本S ...
- IOTOS物联中台从0到1开发modbus_rtu驱动 实例详解
本文章为原创,转载请注明出处! 登录平台:IOTOS®爱投斯物联中台 账号:iotos_test 密码:iotos123 代码地址:IOTOSDK-Python: IOTOS Python版本S ...
- ESP8266 贝壳物联
小白10元玩转智能家居使用天猫精灵+ESP8266WiFi模块对接贝壳物联,可以OLED 屏幕显示温湿度并上传服务器,WiFi控制小车等一系列智能产品 2019-03-24 10:38:17 昂好多个 ...
- 如何用smardaten90天快速开发并上线智慧空间loT物联平台?
前言 大家好,我是小白白,前段时间一位好友接手了一个"烫手山芋"开发任务,77万㎡的科技园区需要打造智慧空间物联平台.要求接入600+园区设备,处理15000+日数据量,在打造整体 ...
最新文章
- 决策树算法python源代码_决的解释|决的意思|汉典“决”字的基本解释
- 【错误记录】Android 分区存储 错误 ( 文件格式不匹配 )
- 使用log4jdbc记录SQL信息
- 内存溢出_JVM|03内存溢出实战
- Django中models利用ORM对Mysql 进行查表的语句(多个语句)
- Fiddler 学习笔记---命令、断点
- Enterprise Vault 10.0.4 FOR Exchange2013 部署之三-日记邮件归档
- 渲染完毕再渲染数据_三星Galaxy S21渲染图再曝:多种配色、新设计
- Android 颜色渲染(三) Shader颜色渲染
- MyEclipse 2014 之 安装JDK 7 与JRE 7 (二)
- python打印图像所有的像素值
- GO语言 使用hash 表
- windows DNS污染解决
- 入门推荐系统,这25篇综述文章足够了
- xp计算机能装win系统吗,自己用的电脑要装系统,XP, Win7, Win10到底选哪个?解救小白篇...
- 大牛耗时一年最佳总结,让你的app体验更丝滑!震撼来袭免费下载!
- 跳动的心html5,施华洛世奇跳动的心真假怎么分辨
- 自定义控件三部曲之动画篇(七)——ObjectAnimator基本使用
- Android程序员如何高薪接私活?十年老炮告诉你,看这一篇就够了
- 使用阿里云短信服务API实现短信验证码以及短信服务通知