python 二次封装Modbus库实现设备间Modbus通信

news2024/12/26 0:08:04

前言:

想想好久没有更博客了,今天忙中偷闲准备写一篇Modbus相关的分享。在进入工业领域之前我一直从事软件行业的测试工作,所以也没听过Modbus协议,但是自从进入西门子工作后正式进入了工业领域,所以对Modbus协议也就不陌生了。

在python中其实已经有了一个pymodbus的第三方模块了,该模块支持对Modbus通讯协议的读写操作,但是在实际使用过程中我们需要在robotframework中构建自动化测试流程,这时原有模块中的函数用起来不是那么顺手,所以就需要对pymodbus模块进行二次封装,封装成ModbusRobot库。

何为Modbus协议?

Modbus协议是什么?对于Modbus协议我特意找了几篇文章: 

文章1: Modbus协议_海底001的博客-CSDN博客

文章2: 详解Modbus通信协议---清晰易懂_Z小旋的博客-CSDN博客_modbus通讯协议 

我觉得已经有人介绍的很清晰了,这里就不过多赘述了哈。

关于封装的介绍

1.建立/断开Modbus连接

	def open_modbus_connection(self, connectionType, **connectParams):
        # 建立modbus连接
		connectionType = ModbusConnectionType[connectionType] if isinstance(connectionType, str) else ModbusConnectionType(connectionType)
		clientID = None

		connectionClass = None
		connectParams.update({
			'timeout': float(connectParams.get('timeout', Defaults.Timeout)),
		})

		if 'unit' not in connectParams:
			unit = int(connectParams.pop('unit', 1))
		else:
			unit = int(connectParams.get('unit'))

		if connectionType in [ModbusConnectionType.TCP, ModbusConnectionType.UDP]:
			connectionTypeMapping = {
				ModbusConnectionType.TCP: {
					'connectionClass': ModbusTcpClient,
					'protocol': 'tcp',
				},
				ModbusConnectionType.UDP: {
					'connectionClass': ModbusUdpClient,
					'protocol': 'udp',
				},
			}

			if 'host' not in connectParams:
				raise ValueError('No host address given for Modbus {:s} connection'.format(connectionType.name))

			connectionClass = connectionTypeMapping[connectionType]['connectionClass']
			connectParams.update({
				'host': connectParams.get('host'),
				'port': int(connectParams.get('port', Defaults.Port)),
			})
			clientID = hashlib.sha1('{:s}://{!s}:{:d}'.format(
				connectionTypeMapping[connectionType]['protocol'],
				connectParams.get('host'),
				connectParams.get('port'),
			).encode('utf-8')).hexdigest()
		elif connectionType == ModbusConnectionType.RTU:
			if 'port' not in connectParams:
				raise ValueError('No COM port given for Modbus {:s} connection'.format(connectionType.name))

			connectionClass = ModbusSerialClient
			connectParams.update({
				'method': 'rtu',
				'port': connectParams.get('port'),
				'baudrate': int(connectParams.get('baudRate', 19200)),
				'parity': connectParams.get('parity', 'E'),
				'stopbits': int(connectParams.get('stopbits', Defaults.Stopbits)),
				'bytesize': int(connectParams.get('bytesize', Defaults.Bytesize)),
			})
			clientID = hashlib.sha1('{:s}'.format(connectParams.get('port')).encode('utf-8')).hexdigest()

		connectionID = '{:s}-{:d}'.format(clientID, unit)

		if clientID not in self._clients:
			self._clients[clientID] = {
				'client': connectionClass(**connectParams),
				'counter': 0,
			}

		if connectionID not in self._connections:
			self._connections[connectionID] = {
				'clientID': clientID,
				'unit': unit,
				'type': connectionType,
			}
			self._clients[clientID]['counter'] += 1

		self._active_connection = connectionID

		return connectionID
	def close_modbus_connection(self, connectionID=None):
        # 断开Modbus连接
		connectionID = self._check_connectionID(connectionID)

		self._clients[self._connections[connectionID]['clientID']]['counter'] -= 1

		if self._clients[self._connections[connectionID]['clientID']]['counter'] <= 0:
			self._clients[self._connections[connectionID]['clientID']]['client'].close()

			del self._clients[self._connections[connectionID]['clientID']]['client']
			del self._clients[self._connections[connectionID]['clientID']]

		del self._connections[connectionID]

		self._active_connection = None if not self._connections else next(iter(self._connections.keys()))

		return self._active_connection

2.根据数据类型读取Modbus数据

	def read_holding_string(self, address, maxLength, connectionID=None):
		connectionID = self._check_connectionID(connectionID)
		response = self._clients[self._connections[connectionID]['clientID']]['client'].read_holding_registers(int(address), int(maxLength / 2), unit=self._connections[connectionID]['unit']) # type: ReadHoldingRegistersResponse

		self._check_respose(response)

		s = struct.pack('!{:s}'.format('H' * len(response.registers)), *response.registers)
		i = -1

		try:
			i = s.index(b'\x00')

			return s[:i].decode('ascii')
		except ValueError:
			return s.decode('ascii')

	def read_holding_float(self, address, connectionID=None):
		connectionID = self._check_connectionID(connectionID)
		response = self._clients[self._connections[connectionID]['clientID']]['client'].read_holding_registers(int(address), 2, unit=self._connections[connectionID]['unit']) # type: ReadHoldingRegistersResponse

		self._check_respose(response)

		return struct.unpack('!f', struct.pack('!HH', *response.registers))[0]

	def read_holding_double(self, address, connectionID=None):
		connectionID = self._check_connectionID(connectionID)
		response = self._clients[self._connections[connectionID]['clientID']]['client'].read_holding_registers(int(address), 4, unit=self._connections[connectionID]['unit']) # type: ReadHoldingRegistersResponse

		self._check_respose(response)

		return struct.unpack('!d', struct.pack('!HHHH', *response.registers))[0]

3.通过Modbus向设备寄存器写数据

	def write_holding_registers(self, address, values, connectionID=None):
		connectionID = self._check_connectionID(connectionID)
		response = self._clients[self._connections[connectionID]['clientID']]['client'].write_registers(int(address), values, unit=self._connections[connectionID]['unit'])

		self._check_respose(response)

		return response

二次封装的库发布

封装完成可以打包成一个可以发布的三方库,结构如下:

下图是结构的介绍,关于打包的方法参考:python自定义包的发布与安装_python自定义包的安装与发布-CSDN博客

 总结

封装完成后可以作为一个单独的三方库,供开发其他功能调用。需要详细的源码可以私信我!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1388987.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chromium+clangd快速代码跳转

在开发chromium的时候我们使用vscode工具进行开发&#xff0c;如果使用C插件发现很容就卡死计算机了。 所以我们使用clangd工具来查看chromium的代码。 一、安装 在vscode中安装还是很简单的。 输入cland&#xff0c;点击安装即可 二、生成编译数据库 代码编译完成后&…

javascript的变量存储机制和原理

前言 在了解javascript的变量存储机制之前需要了解javascript的数据类型&#xff0c;在js中&#xff0c;数据类型分为基本数据类型和引用数据类型。二者存在内存中&#xff0c;基本类型存在栈中&#xff0c;引用类型存储在堆里。 想查看javascript数据类型详细介绍请访问&…

Spring中的事件机制

文章目录 摘要正文jdk事件Spring事件Spring事件监听ApplicationContext主动监听注解监听Bean监听 Spring事件发布 总结 摘要 在这篇文章我们将介绍Spring的事件机制&#xff0c;包括Spring内置事件、自定义事件、事件监听、事件发布、事件广播机制、事件异常处理等内容。Sprin…

Codeforces Round 919 (Div. 2)

Problem - A - Codeforces n个约束条件 a x 求出满足n个约束条件的整数的个数 大于等于x&#xff0c;取最大的 小于等于x&#xff0c;取最小的 然后不等于x的&#xff0c;记录在区间范围内的个数&#xff0c;减去这些 #include<bits/stdc.h> #define endl \n #define …

【前后端的那些事】开源!treeSelect树形结构数据展示

文章目录 tree-selector1. 新增表单组件2. 在父组件中引用3. 父组件添加新增按钮4. 树形组件4.1 前端代码4.2 后端代码 前言&#xff1a;最近写项目&#xff0c;发现了一些很有意思的功能&#xff0c;想写文章&#xff0c;录视频把这些内容记录下。但这些功能太零碎&#xff0c…

快速前端开发01

前端开发 1 前端开发1.快速开发网站2.浏览器能识别的标签2.1 编码&#xff08;head&#xff09;2.2 title&#xff08;head&#xff09;2.3 标题2.4 div和span2.4.5 超链接2.4.6 图片小结2.4.7 列表2.4.8 表格2.4.9 input系列&#xff08;7个&#xff09;2.4.10 下拉框2.4.11 多…

PIFA天线设计经验分享

一、PIFA天线模型分析 从IFA天线的Smith圆图可以看出&#xff0c;其阻抗图随着频率的变化范围十分大&#xff0c;从端口Matrix data中的阻抗数据可以看到这一点。对于WIFI 2.4G频段的应用IFA输入阻抗频宽大致可以满足要求&#xff0c;但是对于其他带宽较宽的应用&#xff0c;该…

Hive 数据迁移

一、需求 同步集团的数据到断直连环境。 二、思路 三、同步数据&#xff08;方案&#xff09; 1、环境&#xff1a;断直连模拟环境 2、操作机器&#xff1a;ETL 机器 XX.14.36.216 3、工作路径&#xff1a;cd /usr/local/fqlhadoop/hadoop/bin 4、执行命令&#xff1a; 命令…

优思学院|质量管理应该看哪些书最好?

很多学员问我们&#xff0c;在探索质量管理博大精深的知识之旅中&#xff0c;应该看哪些书最好&#xff1f;我们推荐学员了解质量管理和精益六西格玛方法的发展史&#xff0c;从中了解质量管理思维的演变&#xff0c;及后再了解质量管理的工具和方法论&#xff08;包括从PDCA、…

系统性学习vue-vue组件化编程

vue组件化编程 对组件的理解使用组件创建组件注册组件编写组件标签注意 组件的嵌套VueComponent构造函数Vue实例与组件实例(vm与vc)一个重要的内置关系单文件组件(项目使用) 对组件的理解 就是将可以复用的模块提取为独立个体, 解决依赖关系混乱,复用率不高的问题 组件: 实现应…

CTF CRYPTO 密码学-2

题目名称&#xff1a;enc 题目描述&#xff1a; 字符 ZZZZ X XXZ ZZ ZXZ Z ZXZ ZX ZZX XXX XZXX XXZ ZX ZXZZ ZZXZ XX ZX ZZ 分析 此字段是由Z和X组成的字符&#xff0c;联想到莫斯密码是由.和-组成的所以接下来可以尝试莫斯密码解题 解题过程&#xff1a; Step1&#xff1a;…

AI编程可视化Java项目拆解第二弹,AI辅助生成方法流程图

之前分享过一篇使用 AI 可视化 Java 项目的文章&#xff0c;同步在 AI 破局星球、知乎、掘金等地方都分享了。 原文在这里AI 编程&#xff1a;可视化 Java 项目 有很多人感兴趣&#xff0c;我打算写一个系列文章拆解这个项目&#xff0c;大家多多点赞支持~ 今天分享的是第二…

四、任意文件读取漏洞

一、介绍 解释&#xff1a;任意文件读取漏洞就其本身来说就是&#xff0c;攻击者绕过网站防御者设置的防御&#xff0c;读取到了正常使用者不应该读取到的内容。网站开发者使用不同的语言&#xff0c;任意文件读取漏洞利用方式就不同。 二、不同开发语言的不同漏洞点 1.PHP …

(更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)

A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数&#xff08;2009-2023年&#xff09;参考《经济研究》中方先明&#xff08;2023&#xff09;的做法&#xff0c;将华证ESG评级进行赋值&#xff0c;指标包含C、CC、CCC、B、BB、BBB、A、AA、AAA共9个等级&#xff0c;…

使用Go语言的HTTP客户端和服务器

使用Go语言进行HTTP客户端和服务器开发是一种高效且强大的方式。Go语言的标准库提供了对HTTP协议的全面支持&#xff0c;使得创建HTTP客户端和服务器变得简单。 首先&#xff0c;让我们来看一下如何创建一个简单的HTTP服务器。在Go中&#xff0c;可以使用net/http包来创建HTTP…

抖音弹幕玩法汉字找不同让鼠标指针自动漂浮的实现原理及代码

如下图&#xff0c;抖音直播间弹幕互动玩法&#xff0c;为了增强用户的视觉感知体验&#xff0c;在里面加了一个鼠标&#xff0c;来让用户感知到自己在操作。下一节我们将背景音乐也给加上去。 我们实现的方案是用anime.js动画&#xff0c;来让一个图片在指定区域范围内随机漂浮…

WebGL开发智慧城市应用

在使用WebGL实现智慧城市应用时&#xff0c;需要考虑一系列的问题&#xff0c;以确保系统的性能、安全性和用户体验。以下是在开发WebGL智慧城市应用时需要注意的问题&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;…

从源码中分析SDS相较于C字符串的优势

文章目录 前言Type && EncodingsdsencodingcreateStringObjectcreateEmbeddedStringObject总结 createRawStringObject总结 createStringObjectFromLongDouble总结 createStringObjectFromLongLongWithOptions总结 相关操作sdscatlen总结 阈值44sds VS C字符串 前言 从…

加密经济学:Web3时代的新经济模型

随着Web3技术的迅猛发展&#xff0c;我们正迈入一个全新的数字经济时代。加密经济学作为这一时代的核心&#xff0c;不仅在数字货币领域崭露头角&#xff0c;更是重新定义了传统经济模型&#xff0c;为我们开启了一个充满创新和机遇的新纪元。 1. 去中心化的经济体系 Web3时代…

12.1、2、3-同步状态机的结构以及Mealy和Moore状态机的区别

同步状态机的结构以及Mealy和Moore状态机的区别 1&#xff0c;介绍Mealy型状态机和Moore型状态机的两种结构2&#xff0c;设计高速电路的方法 由于寄存器传输级&#xff08;RTL&#xff09;描述的是以时序逻辑抽象所得到的有限状态机为依据&#xff0c;因此&#xff0c;把一个时…