python - 如何将字节添加在一起并根据python中的校验和验证它们
问题描述
您如何计算传入字节的校验和以查看它是否是有效数据包?目前我正在读取字节并对其进行解码并接收信息,但在此之前,我希望能够根据校验和对其进行验证,以确保我没有收到任何无效/损坏的数据包。
这是我目前拥有的
def batteryConnect(port, baudrate):
# establishing a serial connection
ser = serial.Serial(port=port, baudrate= baudrate, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE,timeout=3)
return ser
class VictronBmv700:
def __init__(self,port,baudrate):
self.port = port
self.baudrate = baudrate
self.parameterDict = dict.fromkeys(["PID","V","I","P","CE","SOC","TTG","Alarm","Relay","AR","BMV","FW","H1","H2","H3",
"H4","H5","H6","H7","H8","H9","H10","H11","H12","H17","H18"])
def getBMVInfo(self):
bmvdata = batteryConnect(self.port,self.baudrate)
#getting the data
bmvdata.flushInput()
#getting the message then splitting the key, value pairs
while True:
print(bmvdata.readline())
message = bmvdata.readline().decode(encoding='utf-8',errors='ignore')
#splitting on tabs
message_parts = message.split('\t')
if len(message_parts) > 1:
key = message_parts[0]
value = message_parts[1].rstrip() #stripping \r\n after the value
#updating deictionary based on keys and their values.
self.parameterDict[key] = value
if __name__ == "__main__":
print("BATTERY MONITOR")
bmv700 = VictronBmv700("COM17", 19200)
bmv700.getBMVInfo()
开始输出以下内容(来自 print(bmvdata.readline()) )
b'\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd7\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd6\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
如何根据校验和检查传入字节,然后在验证后继续解码?
编辑 有时我会得到不同的校验和值,如下所示。这是我运行代码的另外两次。
b'\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd0\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd7\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd0\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd8\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd8\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd8\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd0\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd0\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd8\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd8\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd8\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd8\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd8\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd8\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd0\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd0\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd0\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd0\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd0\r\n'
b'H2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
第二轮
b'\r\n'
b'V\t25548\r\n'
b'P\t0\r\n'
b'SOC\t1000\r\n'
b'Alarm\tOFF\r\n'
b'AR\t0\r\n'
b'FW\t0310\r\n'
b'H1\t-6254\r\n'
b'H3\t0\r\n'
b'H5\t0\r\n'
b'H7\t-10\r\n'
b'H9\t0\r\n'
b'H11\t0\r\n'
b'H17\t20\r\n'
b'Checksum\tT\r\n'
b'V\t25549\r\n'
b'P\t0\r\n'
b'SOC\t1000\r\n'
b'Alarm\tOFF\r\n'
b'AR\t0\r\n'
b'FW\t0310\r\n'
b'H1\t-6254\r\n'
b'H3\t0\r\n'
b'H5\t0\r\n'
b'H7\t-10\r\n'
b'H9\t0\r\n'
b'H11\t0\r\n'
b'H17\t20\r\n'
b'Checksum\tT\r\n'
b'V\t25548\r\n'
b'P\t0\r\n'
b'SOC\t1000\r\n'
b'Alarm\tOFF\r\n'
b'AR\t0\r\n'
b'FW\t0310\r\n'
b'H1\t-6254\r\n'
b'H3\t0\r\n'
b'H5\t0\r\n'
b'H7\t-10\r\n'
b'H9\t0\r\n'
b'H11\t0\r\n'
b'H17\t20\r\n'
b'Checksum\tT\r\n'
b'V\t25548\r\n'
b'P\t0\r\n'
b'SOC\t1000\r\n'
b'Alarm\tOFF\r\n'
b'AR\t0\r\n'
b'FW\t0310\r\n'
b'H1\t-6254\r\n'
b'H3\t0\r\n'
b'H5\t0\r\n'
b'H7\t-10\r\n'
b'H9\t0\r\n'
b'H11\t0\r\n'
b'H17\t20\r\n'
b'Checksum\tT\r\n'
b'V\t25549\r\n'
b'P\t0\r\n'
b'SOC\t1000\r\n'
b'Alarm\tOFF\r\n'
b'AR\t0\r\n'
b'FW\t0310\r\n'
b'H1\t-6254\r\n'
b'H3\t0\r\n'
b'H5\t0\r\n'
b'H7\t-10\r\n'
b'H9\t0\r\n'
b'H11\t0\r\n'
b'H17\t20\r\n'
b'Checksum\tT\r\n'
b'V\t25548\r\n'
b'P\t0\r\n'
b'SOC\t1000\r\n'
b'Alarm\tOFF\r\n'
b'AR\t0\r\n'
b'FW\t0310\r\n'
b'H1\t-6254\r\n'
b'H3\t0\r\n'
b'H5\t0\r\n'
b'H7\t-10\r\n'
b'H9\t0\r\n'
b'H11\t0\r\n'
b'H17\t20\r\n'
b'Checksum\tT\r\n'
b'V\t25548\r\n'
b'P\t0\r\n'
b'SOC\t1000\r\n'
b'Alarm\tOFF\r\n'
b'AR\t0\r\n'
b'FW\t0310\r\n'
b'H1\t-6254\r\n'
b'H3\t0\r\n'
b'H5\t0\r\n'
b'H7\t-10\r\n'
b'H9\t0\r\n'
b'H11\t0\r\n'
b'H17\t20\r\n'
b'Checksum\tT\r\n'
b'V\t25548\r\n'
b'P\t0\r\n'
b'SOC\t1000\r\n'
b'Alarm\tOFF\r\n'
b'AR\t0\r\n'
b'FW\t0310\r\n'
b'H1\t-6254\r\n'
b'H3\t0\r\n'
b'H5\t0\r\n'
b'H7\t-10\r\n'
b'H9\t0\r\n'
b'H11\t0\r\n'
b'H17\t20\r\n'
b'Checksum\tT\r\n'
b'V\t25548\r\n'
b'P\t0\r\n'
b'SOC\t1000\r\n'
b'Alarm\tOFF\r\n'
b'AR\t0\r\n'
b'FW\t0310\r\n'
编辑 运行以下代码
current_block = []
# it's unfortunate that lines start with `\r\n` rather than end with it
# we will read the first empty line separatey, and then include these
# 2 characters in the last line that is read
message = bmvdata.readline()
while True:
# Note that we cannot decode yet, since the Checksum value may not be a valid utf8 character
message = bmvdata.readline()
# we save the message in the current block before any preprocessing
current_block.append(message)
#splitting on tabs (as bytes !!)
message_parts = message.split(b'\t')
if len(message_parts) > 1:
key = message_parts[0].decode('utf8') # here it is safe to decode the key
value = message_parts[1].rstrip() #stripping \r\n after the value
if key == 'Checksum':
block_chars = b''.join(current_block)
checksum = sum(block_chars) % 256
print('Retrieved checksum', value[-1])
print('Calculated checksum', checksum)
print('----')
# reset the block
current_block = []
输出
Retrieved checksum 84
Calculated checksum 0
-------
Retrieved checksum 219
Calculated checksum 0
-------
Retrieved checksum 84
Calculated checksum 0
-------
Retrieved checksum 220
Calculated checksum 0
-------
Retrieved checksum 84
Calculated checksum 0
-------
Retrieved checksum 219
Calculated checksum 0
-------
Retrieved checksum 84
Calculated checksum 0
-------
Retrieved checksum 219
Calculated checksum 0
-------
Retrieved checksum 84
Calculated checksum 0
-------
Retrieved checksum 220
Calculated checksum 0
-------
Retrieved checksum 84
Calculated checksum 0
-------
Retrieved checksum 220
Calculated checksum 0
-------
Retrieved checksum 84
Calculated checksum 0
-------
Retrieved checksum 220
Calculated checksum 0
-------
Retrieved checksum 84
Calculated checksum 0
-------
Retrieved checksum 219
Calculated checksum 0
-------
Retrieved checksum 84
Calculated checksum 0
-------
解决方案
看来张贴者正试图从 BMV700 电池监视器读取数据。阅读这里的论文,我们看到它使用文本协议通过串行接口进行通信:
2 文本协议
当没有向设备发送 VE.Direct 查询时,充电器会定期向串行端口发送人类可读 (TEXT) 数据。有关信息内容和可用性的详细说明,请参阅“VE.Direct 协议”文档
HEX 协议摘录 (BMV-7xx-HEX-Protocol-public.pdf)
查看 TEXT 协议的规范(VE.Direct-Protocol-3.28.pdf),我们发现:
消息格式
设备以 1 秒的间隔传输数据块。每个字段都使用以下格式发送:
<Newline><Field-Label><Tab><Field-Value>
标识符定义如下:
+---------------+--------------------------------------------------------------------------------------+ | Identifier | Meaning | +===============+======================================================================================+ | <Newline> | A carriage return followed by a line feed (0x0D, 0x0A). | +---------------+--------------------------------------------------------------------------------------+ | <Field-Label> | An arbitrary length label that identifies the field. | | | Where applicable, this will be the same as the label that is used on the LCD. | +---------------+--------------------------------------------------------------------------------------+ | <Tab> | A horizontal tab (0x09). | +---------------+--------------------------------------------------------------------------------------+ | <Field-Value> | The ASCII formatted value of this field. | | | The number of characters transmitted depends on the magnitude and sign of the value. | +---------------+--------------------------------------------------------------------------------------+
这与您正在打印的数据相对应,但有一个例外:该行以 开头,\r\b
但不以它们结尾。
然后,该文件提供了有关校验和的详细信息:
数据的完整性
统计信息按块分组,并附加校验和。块中的最后一个字段将始终是“校验和”。该值是单个字节,不一定是可打印的 ASCII 字符。如果没有传输错误,则块中所有字节的模 256 总和将等于 0。发送包含不同字段的多个块。
因此,在您作为输出发布的摘录中,您有两个完整的块和一个不完整的块,因为最后一个块缺少Checksum
.
block = (b'\r\nH2\t0\r\n'
b'H4\t0\r\n'
b'H6\t-9001\r\n'
b'H8\t28403\r\n'
b'H10\t0\r\n'
b'H12\t0\r\n'
b'H18\t87\r\n'
b'PID\t0x203\r\n'
b'I\t0\r\n'
b'CE\t0\r\n'
b'TTG\t-1\r\n'
b'Relay\tOFF\r\n'
b'BMV\t700\r\n'
b'Checksum\t\xd6')
请注意,我\r\n
在开头添加了 ,并从块的末尾删除了它们,这样最后一个字节就是块的校验和。
现在,我们可以计算块的校验和:
>>> sum(block) % 256
213
这应该是零。因此,可能存在一些传输问题,或者他们计算校验和的方式可能与他们在文档中所说的不同。
新数据后编辑。
这是我用来检查您发布的所有块的代码:
current_block = []
# it's unfortunate that lines start with `\r\n` rather than end with it
# we will read the first empty line separatey, and then include these
# 2 characters in the last line that is read
message = bmvdata.readline()
while True:
# Note that we cannot decode yet, since the Checksum value may not be a valid utf8 character
message = bmvdata.readline()
# we save the message in the current block before any preprocessing
current_block.append(message)
#splitting on tabs (as bytes !!)
message_parts = message.split(b'\t')
if len(message_parts) > 1:
key = message_parts[0].decode('utf8') # here it is safe to decode the key
value = message_parts[1].rstrip() #stripping \r\n after the value
if key == 'Checksum':
block_chars = b''.join(current_block)
checksum = sum(block_chars) % 256
print('Retrieved checksum', value[-1])
print('Calculated checksum', checksum)
print('----')
# reset the block
current_block = []
奇怪的是,对于第一次运行,您总是得到等于检索 + 1 的计算值,但在第二次运行中却不是。因此,可能存在一些传输问题。
推荐阅读
- amazon-web-services - AWS 主路由表
- c# - LINQ 语法:如何有相同的目的?
- python-3.x - 使用python从html文件中的多个表中获取特定表
- emeditor - 使用 Emeditor 将 unicode 字符转换为可读格式?
- function - How can I use Perl's format function?
- c# - 如何为 AzureServiceBus 主题配置 RequiresDuplicateDetection
- android - 在代理连接下未找到适用于 Android 的信任锚
- php - Codeigniter 3,绑定参数是否可以保护我免受 SQL 注入?
- php - PHP - 将输入文件的值从一页转移到另一页
- css - CSS Grid 仅设置顶行的列数