当前位置: 首页 > news >正文

14、监测数据采集物联网应用开发步骤(10)

  1. 监测数据采集物联网应用开发步骤(9.2)

Modbus rtu协议开发

本章节在《监测数据采集物联网应用开发步骤(7)》基础上实现可参考《...开发步骤(7)》调试工具,本章节代码需要调用modbus_tk组件阅读本章节前建议baidu熟悉modbus rtu协议内容

组件安装modbus_tk

pip3 install modbus_tk

验证是否安装成功,python中运行下列代码无异常则安装成功:

import modbus_tk

新建modbus协议管理类com.zxy.comport.ComModBus.py

#! python3
# -*- coding: utf-8 -
'''
Created on 2020年05月10日
@author: zxyong 13738196011
'''
import time,struct
from com.zxy.common import Com_Para
from com.zxy.common.Com_Fun import Com_Fun
from com.zxy.z_debug import z_debug
import modbus_tk.defines as cst
import modbus_tk.modbus_rtu as modbus_rtu#监测数据采集物联网应用--modbus协议管理类
class ComModBus(z_debug):def __init__(self):pass@staticmethoddef get_objAryRtuMaster(inputComPort):        master = Com_Fun.GetHashTableNone(Com_Para.objAryRtuMaster, inputComPort)if master is None:com_at = Com_Fun.GetHashTableNone(Com_Para.htComPort, inputComPort)if com_at is not None:master = modbus_rtu.RtuMaster(com_at.attSerial)           # 设定串口为从站master.set_timeout(5.0)master.set_verbose(True)Com_Fun.SetHashTable(Com_Para.objAryRtuMaster, inputComPort, master)return master#字符串转16进制字节并+crc16校验,传入参数无crc校验@staticmethoddef get_data_com_nocrc(inputComPort, CmdStr):  temReturn = None       try:  com_at = Com_Fun.GetHashTable(Com_Para.htComPort, inputComPort)  inputByte = bytes().fromhex(CmdStr)inputByte = inputByte + ComModBus._getCrc16(inputByte)if com_at.WritePortData(inputByte) > 0:temReturn = com_at.attReturnValue                    com_at.attReturnValue = Noneexcept Exception as e:temReturn = Nonereturn temReturn#字符串转字节发送,ascii发送@staticmethoddef get_data_com_ascii(inputComPort, CmdStr):  temReturn = None       try:  com_at = Com_Fun.GetHashTable(Com_Para.htComPort, inputComPort)inputByte = bytes(CmdStr, encoding="utf8")if com_at.WritePortDataImmed(inputByte) > 0:temReturn = com_at.attReturnValue                    com_at.attReturnValue = Noneexcept Exception as e:temReturn = Nonereturn temReturn#字符串转16进制字节发送@staticmethoddef get_data_com_hex(inputComPort, CmdStr):     temReturn = None    try:com_at = Com_Fun.GetHashTable(Com_Para.htComPort, inputComPort)  inputByte = bytes().fromhex(CmdStr)if com_at.WritePortData(inputByte) > 0:comValue = com_at.attReturnValueif comValue is None:return NonetemReturn = comValuecom_at.attReturnValue = Noneexcept Exception as e:temReturn = Nonereturn temReturn#字节发送@staticmethoddef get_data_com_byte(inputComPort, inputByte):    temReturn = None     try:com_at = Com_Fun.GetHashTable(Com_Para.htComPort, inputComPort)  if com_at.WritePortData(inputByte) > 0:comValue = com_at.attReturnValueif comValue is None:return NonetemReturn = comValuecom_at.attReturnValue = Noneexcept Exception as e:temReturn = Nonereturn temReturn#Modbus 04功能码发送@staticmethoddef get_data_rtu_04(inputComPort, inputModbusAddr, inputModbusBegin, inputModbusLength):red = []try:master = ComModBus.get_objAryRtuMaster(inputComPort)if master is not None:red = master.execute(int(inputModbusAddr), cst.READ_INPUT_REGISTERS, int(inputModbusBegin), int(inputModbusLength))  # 这里可以修改需要读取的功能码             time.sleep(0.1)                if isinstance(red, list) or isinstance(red, tuple): return redelse:return [""]except Exception as e:return [""]#Modbus 03功能码发送 @staticmethoddef get_data_rtu_03(inputComPort, inputModbusAddr, inputModbusBegin, inputModbusLength):read = []try:master = ComModBus.get_objAryRtuMaster(inputComPort)if master is not None:read = master.execute(inputModbusAddr, cst.READ_HOLDING_REGISTERS, inputModbusBegin, inputModbusLength)  # 这里可以修改需要读取的功能码             time.sleep(0.1)                if isinstance(read, list) or isinstance(read, tuple): return readelse:return [""]except Exception as e:return [""]#Modbus 写寄存器数据@staticmethoddef set_data_rtu(inputComPort, inputModbusAddr, inputModbusBegin, inputValue):read = []try:master = ComModBus.get_objAryRtuMaster(inputComPort)if master is not None:# 这里可以修改需要读取的功能码 if isinstance(inputValue, list) or isinstance(read, tuple):read = master.execute(inputModbusAddr, cst.WRITE_MULTIPLE_REGISTERS, inputModbusBegin, output_value=inputValue) else:read = master.execute(inputModbusAddr, cst.WRITE_SINGLE_REGISTER, inputModbusBegin, output_value=inputValue)               if isinstance(read, list) or isinstance(read, tuple): return readelse:return [""]except Exception as e:return [""]@staticmethoddef set_data_rtu2(inputComPort, inputModbusAddr, inputModbusBegin, inputValue):read = []try:master = ComModBus.get_objAryRtuMaster(inputComPort)if master is not None:# 这里可以修改需要读取的功能码 if isinstance(inputValue, list) or isinstance(read, tuple):read = master.execute(inputModbusAddr, cst.ANALOG_INPUTS, inputModbusBegin, output_value=inputValue) else:read = master.execute(inputModbusAddr, cst.ANALOG_INPUTS, inputModbusBegin, output_value=inputValue)               if isinstance(read, list) or isinstance(read, tuple): return readelse:return [""]except Exception as e:return [""]@staticmethoddef _getCrc16(RtuStr):b = 0xA001# 16位寄存器a = 0xFFFFfor byte in RtuStr:# 1、把数据帧中的第一个8位字节与CRC寄存器中的低字节进行异或运算a = a ^ bytefor i in range(8):# 3、如果最低位为1:将CRC寄存器与一个预设的固定值(0A001H)进行异或运算if a & 0x0001:a = a >> 1a = a ^ b # 2、将CRC寄存器向右移一位,最高位填以0,最低位移出并检测else:a = a >> 1aa = '0' * (6 - len(hex(a))) + hex(a)[2:]# 获取低和高位lo, hh = int(aa[:2], 16), int(aa[2:], 16)hexbytes = bytes([hh, lo])return hexbytes#高低位 reverse: true高位在前 false低位在前@staticmethoddef ReadFloat(n1, n2, reverse=False):    n = '%04x' % n1m = '%04x' % n2if reverse:v = n + melse:v = m + ny_bytes = bytes.fromhex(v)y = struct.unpack('!f', y_bytes)[0]y = round(y, 6)return y@staticmethoddef WriteFloat(value, reverse=False):y_bytes = struct.pack('!f', value)y_hex = ''.join(['%02x' % i for i in y_bytes])n, m = y_hex[:-4], y_hex[-4:]n, m = int(n, 16), int(m, 16)if reverse:v = [n, m]else:v = [m, n]return v@staticmethoddef ReadDint(n1,m1, reverse=False):n ='%04x' % n1m = '%04x' % m1if reverse:v = n + melse:v = m + ny_bytes = bytes.fromhex(v)y = struct.unpack('!i', y_bytes)[0]return y@staticmethoddef WriteDint(value, reverse=False):y_bytes = struct.pack('!i', value)y_hex = ''.join(['%02x' % i for i in y_bytes])n, m = y_hex[:-4], y_hex[-4:]n, m = int(n, 16), int(m, 16)if reverse:v = [n, m]else:v = [m, n]return v

modbus rtu测试案例MonitorDataCmd.py主文件中编写:

from com.zxy.comport.ComModBus import ComModBus

在    if __name__ == '__main__':下添加

        #串口配置参数Com_Para.ComPortList = "COM2,9600,8,0,A;COM4,9600,8,2,B"#串口连接初始化Init_Page.Start_ComPort()#Modbus-rtu协议功能测试temA01modbus = ComModBus()#利用modbus_tk组件获取数据,参数:COM索引,modbus站地址,modbus起始位,modbus长度read = temA01modbus.get_data_rtu_03("A",1,0,10)print("获取10进制原始返回值=>"+str(read))modValue = []iIndex = 0.0n1 = 0n2 = 0for temSV in read:if iIndex % 2 != 0:n2 = int(temSV)#16进制单精转浮点temMV = temA01modbus.ReadFloat(n1,n2,True)modValue.append(temMV)else:n1 = int(temSV)iIndex = iIndex + 1print("获取读到并解析的寄存器浮点数=>"+str(modValue))#利用modbus指令协议直接通过com口读取数据temCmd = "010300A1000A942F"bhex = temA01modbus.get_data_com_hex("A",temCmd)read = str(binascii.b2a_hex(bhex).decode(Com_Para.U_CODE)).upper()print("获取16进制返回值=>"+str(read))

运行测试结果如下图:

测试案例中例举了2种方法都可以读到数据,任取其一即可。

针对        

#利用modbus指令协议直接通过com口读取数据

      temCmd = "010300A1000A942F"

指令解释如下:

01 站地址

03 功能码

00A1 寄存器开始地址(16进制)

000A  读取数据长度10个(16进制转10进制)

942F CRC校验码

获取16进制返回值=>010314429DA8F643060A3D420070A44343000043554CCD49A8返回值解释如下:

01 站地址

03 功能码

14 数据长度20(16进制转10进制)

429DA8F643060A3D420070A44343000043554CCD 数据值16进制

49A8 CRC校验码

429DA8F643060A3D420070A44343000043554CCD 数据值解析要依据相关对方开发说明文档,假设该数据为寄存器浮点数则按如下解析:

429D A8F6 ==>10进制浮点数 78.83

4306 0A3D ==>10进制浮点数 134.039

4200 70A4 ==>10进制浮点数 32.11

4343 0000 ==>10进制浮点数 195

4355 4CCD ==>10进制浮点数 213.300

可以利用该工具计算IEEE 754浮点数十六进制相互转换(32位,四字节,单精度)

在线进制转换-IEE754浮点数16进制转换

相关文章:

14、监测数据采集物联网应用开发步骤(10)

监测数据采集物联网应用开发步骤(9.2) Modbus rtu协议开发 本章节在《监测数据采集物联网应用开发步骤(7)》基础上实现可参考《...开发步骤(7)》调试工具,本章节代码需要调用modbus_tk组件,阅读本章节前建议baidu熟悉modbus rtu协议内容 组件安装modb…...

Linux禅道上修改Apache 和 MySQL 默认端口号

1. 修改Apache默认端口号 80 cd /opt/zbox/etc/apachevim httpd.conf :wq 保存 2. 修改MySQL默认端口号 3306 cd /opt/zbox/etc/mysql vim my.cnf :wq 保存 3. 重启服务 ./zbox restart...

操作教程|通过1Panel开源Linux面板快速安装DataEase

DataEase开源数据可视化分析工具(dataease.io)的在线安装是通过在服务器命令行执行Linux命令来进行的。但是在实际的安装部署过程中,很多数据分析师或者业务人员经常会因为不熟悉Linux操作系统及命令行操作方式,在安装DataEase的过…...

机器学习策略——优化深度学习系统

正交化(Orthogonalization) 老式电视机,有很多旋钮可以用来调整图像的各种性质,对于这些旧式电视,可能有一个旋钮用来调图像垂直方向的高度,另外有一个旋钮用来调图像宽度,也许还有一个旋钮用来…...

ES6中Proxy和Proxy实例

1.Proxy Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器” 使用方法 let p new Proxy(target, handler);其中,target 为被代理对象。handler 是一个对象,其声明了代理 target 的一些操作。p 是…...

UDP协议的重要知识点

UDP,即用户数据报协议(User Datagram Protocol),是一个简单的无连接的传输层协议。与TCP相比,UDP提供了更少的错误检查机制,并允许数据包在网络上更快地传输。在这篇博客中,我们将深入探讨UDP的…...

QT6为工程添加资源文件,并在ui界面引用

以添加图片资源为例 右键工程名字(不是最上面的名字),点击添加现有文件 这种方式虽然添加到了工程中,但不能在UI设计界面完成引用。主要原因可能是未把文件放入到项目资源文件中,以下面一种方式可以看出区别。 点击添…...

Python小知识 - 如何使用Python的Flask框架快速开发Web应用

如何使用Python的Flask框架快速开发Web应用 现在越来越多的人把Python作为自己的第一语言来学习,Python的简洁易学的语法以及丰富的第三方库让人们越来越喜欢上了这门语言。本文将介绍如何使用Python的Flask框架快速开发Web应用。 Flask是一个使用Python编写的轻量级…...

Flutter 项目结构文件

1、Flutter项目的文件结构 先helloworld项目,看看它都包含哪些组成部分。首先,来看一下项目的文件结构,如下图所示。 2、介绍上图的内容。 -litb/main.dart文件:整个应用的入口文件,其中的main函数是整个Flutter应…...

未找到System.Runtime.InteropServices.Marshal.GetTypeFromCLSID(System.Guid) 方法错误

记录此问题实际上是由于.netFrame框架配置太高引起的,一般常见于二次开发中,因为二次开发一般都是引用的com组件,在引用过程中后台代码调用了 Method not found: System.Type System.Runtime.InteropServices.Marshal.GetTypeFromCLSID(Syste…...

人员位置管理,点亮矿山安全之路

矿山作为一个高危行业,安全问题一直备受关注。人员定位置管理是现代矿山安全管理的重要一环,可以帮助企业更好地实现对人员的实时监控和管理。因此,矿山人员位置管理系统对于矿山安全生产和管理非常重要,可以帮助减少安全事故的发…...

node-red - 读写操作redis

node-red - 读写操作redis 一、前期准备二、node-red安装redis节点三、node-red操作使用redis节点3.1 redis-out节点 - 存储数据到redis3.2 redis-cmd节点 - 存储redis数据3.3 redis-in节点 - 查询redis数据 附录附录1:redis -out节点示例代码附录2:redi…...

【图像处理】模板匹配的学习笔记

OpenCV的模板匹配算法 cv.TM_CCOEFFcv.TM_CCOEFF_NORMEDcv.TM_CCORRcv.TM_CCORR_NORMEDcv.TM_SQDIFFcv.TM_SQDIFF_NORMED 匹配代码模板 image cv2.imread(r"scene.png", cv2.IMREAD_GRAYSCALE) template cv2.imread(r"element.png", cv2.IMREAD_GRAYSC…...

Ext JS之Ext Direct快速入门

Ext Direct是一个专有名词, Direct是直接的意思。 Ext Direct 是 Ext JS 框架中的一个功能模块,用于简化前端 JavaScript 应用程序与后端服务器之间的通信和数据交换。 Ext Direct 提供了一种直接的、透明的方式来调用服务器上的方法和处理服务器响应,而无需编写大量的手动…...

内网隧道技术学习

1. 隧道技术 在进行渗透测试以及攻防演练的时候,通常会存在各种边界设备、软硬件防火墙、IPS等设备来检测外部连接情况,这些设备如果发现异常,就会对通信进行阻断。 那么隧道技术就是一种绕过端口屏蔽的通信方式,在实际情况中防…...

【前端】CSS3新特性

目录 一、前言二、伪元素选择器1、选择器2、注意事项3、代码示例 三、伪元素清除浮动1、第一种伪元素清除浮动2、第二种伪元素清除浮动 四、CSS3盒子模型1、box-sizing:content-box2、box-sizing:border-box 五、CSS3图片模糊处理1、图片变模糊①、CSS3滤…...

Spring之HandlerInterceptor和RequestBodyAdvice

一个请求在Spring中处理流程是有多种方式拦截处理的,而且,请求是可以拆分为进入和响应2个操作的,进入我们通常会对请求参数做处理,而响应我们通常会对响应参数做处理,Spring提供了多种方式给开发者。 一、HandlerInte…...

transition、transform 区别和应用

先说应用 1.动画循环,复杂的动画用animation。在遇到很复杂的动画那就用animation。因为animation可以定义关键帧。那你就可以控制每一帧的动画效果。 2.简单的动画,事件触发用transition。当页面中的动画是自己执行的那么我们考虑用animation&#xf…...

Android中级——消息机制

消息机制 概念ThreadLocalMessageQueueLooperHandlerrunOnUiThread() 概念 MessageQueue:采用单链表的方法存储消息列表Looper:查询MessageQueue是否有新消息,有则处理,无则等待ThreadLocal:用于Handler获取当前线程的…...

【kubernetes】使用KubeSphere devops部署我的微服务系统

KubeSphere Devops 入门使用KubeSphere的Devops功能部署"我的微服务系统" (内容学习于尚硅谷云原生课程) kubesphere devops官方文档: https://v3-1.docs.kubesphere.io/zh/docs/devops-user-guide/how-to-use/create-a-pipeline-u…...

【哈士奇赠书活动 - 37期】- 〖深入浅出SSD:固态存储核心技术、原理与实战 第2版〗

文章目录 ⭐️ 赠书 - 《深入浅出SSD:固态存储核心技术、原理与实战 第2版》⭐️ 内容简介⭐️ 作者简介⭐️ 编辑推荐⭐️ 赠书活动 → 获奖名单 ⭐️ 赠书 - 《深入浅出SSD:固态存储核心技术、原理与实战 第2版》 ⭐️ 内容简介 本书从基础认知、核心技…...

25.CSS自定义形状按钮与悬停效果

效果 源码 <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>CSS Custom Shape Button</title><link rel="stylesheet" href="style.css"> </head> <body&…...

两条速度相差1350倍的sql语句

一起来学习研究下&#xff0c;看看是什么导致的这么大差别&#xff1a; SQL1: select * from RESOURCES where RES_STATUS 1 and PLATFORM_FLAG1 and RES_ID in (select RES_ID from DOWNLOADRECORDSwhere DOWNLOADRECORDS_TIME > DATE_SUB(now(),INTERVAL 7 DAY) grou…...

【UniApp开发小程序】小程序首页完善(滑到底部数据翻页、回到顶端、基于回溯算法的两列数据高宽比平衡)【后端基于若依管理系统开发】

文章目录 说明细节一&#xff1a;首页滑动到底部&#xff0c;需要查询下一页的商品界面预览页面实现 细节二&#xff1a;当页面滑动到下方&#xff0c;出现一个回到顶端的悬浮按钮细节三&#xff1a;商品分列说明优化前后效果对比使用回溯算法实现ControllerService回溯算法 优…...

使用errors.Wrapf()代替log.Error()

介绍不同语言的错误处理机制: Error handling patterns[1] Musings about error handling mechanisms in programming languages[2] 项目中 main调func1&#xff0c;func1调取func2... 这样就会出现很多的 if err ! nil { log.Printf()} , 在Kibana上查看时会搜到多条日志, 需要…...

企业面临的IP风险,如何应对?

IP风险画像为企业或组织在知识产权领域面临的潜在风险和威胁的综合概览。通过对相关知识产权的保护和管理&#xff0c;企业可以预测和应对潜在的法律、商业和声誉风险。 IP数据云帮助企业更好地了解和应对知识产权方面的风险。并提供了关于当前全球知识产权环境的重要信息&…...

L1-046 整除光棍(Python实现) 测试点全过

题目 这里所谓的“光棍”&#xff0c;并不是指单身汪啦~ 说的是全部由1组成的数字&#xff0c;比如1、11、111、1111等。传说任何一个光棍都能被一个不以5结尾的奇数整除。比如&#xff0c;111111就可以被13整除。 现在&#xff0c;你的程序要读入一个整数x&#xff0c;这个整…...

《Web安全基础》04. 文件上传漏洞

web 1&#xff1a;文件上传漏洞2&#xff1a;WAF 绕过2.1&#xff1a;数据溢出2.2&#xff1a;符号变异2.3&#xff1a;数据截断2.4&#xff1a;重复数据 本系列侧重方法论&#xff0c;各工具只是实现目标的载体。 命令与工具只做简单介绍&#xff0c;其使用另见《安全工具录》…...

文本匹配实战系列

引言 本系列文章开始介绍深度学习在文本匹配领域的应用&#xff0c;并且会尝试得到各种模型在给定的数据集上的表现。 深度文本匹配发展比较久&#xff0c;积累了很多文本匹配方法。也有很多的分类方式&#xff0c;一种分类方式是表示型和交互型。 表示型方法 表示型(repre…...

【Kafka】Kafka Stream简单使用

一、实时流式计算 1. 概念 一般流式计算会与批量计算相比较。在流式计算模型中&#xff0c;输入是持续的&#xff0c;可以认为在时间上是无界的&#xff0c;也就意味着&#xff0c;永远拿不到全量数据去做计算。同时&#xff0c;计算结果是持续输出的&#xff0c;也即计算结果…...