#!/usr/bin/env python3
#author: aizhen
#version: 0.1
#desc: RTU
#date: 2022-03-21
import socket
import base64
import crcmod
import binascii
import sys
def CRCAdd(read):
'''生成CRC16校验码,CRC16/modbus'''
crc16 = crcmod.mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000)
rawdata = read.replace(" ", "")
#修正后数据
#print(rawdata)
#字符串变数
data = binascii.unhexlify(rawdata)
readcrcout = hex(crc16(data)).upper()
#print(readcrcout)
str_list = list(readcrcout)
# print(str_list)
# 位数不足补0,因为一般最少是5个
if len(str_list) == 5:
str_list.insert(2, '0')
#用""把数组的每一位结合起来组成新的字符串
crc_data = "".join(str_list)
#生成CRC校验
#print(crc_data)
#print('CRC16校验: %s' % (crc_data[4:] + ' ' + crc_data[2:4]))
#高低位判断,高位在前,低位在后原则
CRC1=int(crc_data[4:], 16)
CRC2=int(crc_data[2:4], 16)
read = rawdata + crc_data[4:] + crc_data[2:4]
# print(crc_data[4:],crc_data[2:4])
'''
if CRC1 > CRC2:
high_CRC=crc_data[4:]
low_CRC=crc_data[2:4]
else:
high_CRC=crc_data[2:4]
low_CRC=crc_data[4:]
read = rawdata + high_CRC + low_CRC
'''
# print (read)
# print (type(read))
#print('增加Modbus_CRC16校验:>>> %s' % read)
# print(read)
return read
def ModbusRTU():
'''python3 调用socket连接串口服务器(网络适配器)以modbusRTU方式发送16进制报文,进行数据采集,'''
ip = str(sys.argv[1])
port = int(sys.argv[2])
msg = sys.argv[3]
msg = msg.replace(" ", "")
msg_test = msg
# print(msg_test[4:8])
# print(msg_test)
msg_test = msg_test[4:8]
# print(msg_test)
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#增加CRC校验码
msg_CRC = CRCAdd(msg)
#连接超时时间
s.settimeout(5)
s.connect((ip, port))
#将代码转换成16进制字节
msg_CRC = bytes.fromhex(msg_CRC)
# print(msg_CRC)
# print(type(msg_CRC))
#proint(msg_CRC)
# print(msg_CRC)
s.send(msg_CRC)
rawdata = s.recv(2048)
# print(rawdata)
# print(rawdata)
#print(rawdata)
#关闭TCP连接
s.close()
#数据处理,将字节转换成16进制
data = base64.b16encode(rawdata).decode('ascii')
# print(data)
#0404需要转换为二进制
if msg_test =="0404":
#再取一次数据,确保数据没有问题
if data[6:10]!="0003":
msg_test = msg
msg_test = msg_test[4:8]
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
msg_CRC = CRCAdd(msg)
s.settimeout(5)
s.connect((ip, port))
msg_CRC = bytes.fromhex(msg_CRC)
s.send(msg_CRC)
rawdata = s.recv(2048)
s.close()
data = base64.b16encode(rawdata).decode('ascii')
B_count = int(int(data[4:6], 10) / 2)
B_first = 6
B_end = 10
dataInfo = []
B_data = data[6:10]
B_data = int(B_data, 16)
B_data = bin(B_data).replace("0b","")
dataInfo.append(B_data)
B_count-=1
while B_count > 0:
B_first+=4
B_end+=4
B_data = data[B_first:B_end]
B_data = bin(int(B_data, 16)).replace("0b","")
dataInfo.append(B_data)
B_count-=1
else:
B_count = int(int(data[4:6], 10) / 2)
B_first = 6
B_end = 10
dataInfo = []
B_data = data[6:10]
B_data = int(B_data, 16)
B_data = bin(B_data).replace("0b","")
dataInfo.append(B_data)
B_count-=1
while B_count > 0:
B_first+=4
B_end+=4
B_data = data[B_first:B_end]
B_data = bin(int(B_data, 16)).replace("0b","")
dataInfo.append(B_data)
B_count-=1
else:
#获取返回字节数,得到具体个数
B_count = int(int(data[4:6], 10) / 2)
#数据长度为2字节,长度为4
#将数据转化为十进制
B_first = 6
B_end = 10
dataInfo = []
B_data = data[6:10]
B_data = int(B_data, 16)
dataInfo.append(B_data)
# print(dataInfo)
B_count-=1
while B_count > 0:
B_first+=4
B_end+=4
B_data = data[B_first:B_end]
B_data = int(B_data, 16)
dataInfo.append(B_data)
B_count-=1
# print(dataInfo)
#print(dataInfo)
#以相关项方式采集数据,以:分割
# print(dataInfo)
#条件判断属于华为告警
# data="11030200087841"
#msg_test取的是基础寄存地址,属于告警的寄存地址
#data[6:10]是返回的数据为16进制,需要转化为二进制
#转化为二进制后0为正常,1为告警
#而且二进制需要反序,查看bit位,需要对应起来,因为bit位最多为16位,就需要补全
# data="1103020012F846"
if msg_test=="9CDB" or msg_test=="9CDC" or msg_test=="9CDE" or msg_test=="9CDF" or msg_test=="9CE0" or msg_test=="9CE1" or msg_test=="9CE3" or msg_test=="9CE4" or msg_test=="9CE5" or msg_test=="9CE8" or msg_test=="9CE9" or msg_test=="9CEA" or msg_test=="9CEB" or msg_test=="9CEC" or msg_test=="9CED" or msg_test=="9CEE" or msg_test=="9CF3" or msg_test=="9CF4" or msg_test=="9CF6" or msg_test=="9CF7":
#再运行一次,确保数据准确性
if data[6:10]!="0000":
# print("-------")
msg_test = msg
msg_test = msg_test[4:8]
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
msg_CRC = CRCAdd(msg)
s.settimeout(5)
s.connect((ip, port))
msg_CRC = bytes.fromhex(msg_CRC)
s.send(msg_CRC)
rawdata = s.recv(2048)
s.close()
data = base64.b16encode(rawdata).decode('ascii')
# print("-------")
if data[6:10]=="0000":
# print(data)
data="0000000000000000"
d=-1
for i in data:
d+=1
print("B%s=%s" % (d,i), end=" ")
else:
# print(data)
data_bin=bin(int(data[6:10],16))[2:]
data_list=list(data_bin)
end_list=[]
for i in range(16-len(data_bin)):
end_list.append(0)
for i in data_list:
end_list.append(i)
end_list.reverse()
d=-1
for i in end_list:
d+=1
print("B%s=%s" % (d,i), end=" ")
if data[6:10]=="0000":
# print(data)
data="0000000000000000"
d=-1
for i in data:
d+=1
print("B%s=%s" % (d,i), end=" ")
# else:
# # print(data)
# data_bin=bin(int(data[6:10],16))[2:]
# data_list=list(data_bin)
# end_list=[]
# for i in range(16-len(data_bin)):
# end_list.append(0)
# for i in data_list:
# end_list.append(i)
# end_list.reverse()
# d=-1
# for i in end_list:
# d+=1
# print("B%s=%s" % (d,i), end=" ")
else:
# print(dataInfo)
for i in dataInfo:
print(i, end=' ')
if __name__ == '__main__':
#脚本执行示例
# python3 modbus-RTU.py '192.168.109.242' 8234 '01 03 00 01 00 01'
ModbusRTU()