Форум сайта python.su
Доброго времени суток
Просьба помочь разобраться с ребусом по опросу теплосчетчика SANEXT Mono RM по RS485
Есть описание формата данных
https://imgur.com/J6SwXrK
https://imgur.com/nOzvkYr
Есть Raspberry pi 3 b и rs485 to usb
И огромное желание разобраться как собрать данные )
Планировал использовать готовую библиотеку minimalmodbus для питона с режимом RTU.
Но не осилил синтаксис. Точнее не осилил в целом логику синтаксиса передачи и получения данных по RS485 даже просто в режиме СОМ порта.
Единственное пока, что понял из найденных примеров что нужно передавать данные в НЕХ. Еще как то нужно CRC16 посчитать и куда то деть. В общем непонятно ни чего от слова совсем.
Примеров под мой случай толковых не нашел. Буду очень признателен за помощь в решении этого ребуса. Мне по сути нужно вытащить один показатель только.
https://github.com/n0l/Mercury_remote/blob/master/get_data_python3.py
нашел очень близкий пример по реализации, но не понимаю части логики кода….
Отредактировано Akhepython (Дек. 21, 2021 18:13:19)
Офлайн
import crcmod # def crc16_calc(chunk): # считает crc16 crc16 = crcmod.mkCrcFun(0x18005, initCrc=0xFFFF, rev=True, xorOut=0x0000) crc_int = crc16(chunk) high_byte = crc_int >> 8 low_byte = crc_int & 0xff out_hex = '{:02X}{:02X}'.format(low_byte, high_byte) return bytes.fromhex(out_hex) # def create_package(addr, f, l, mask_ch, id) -> bytes: # собирает пакет hex_chunk = '{:08d}{:02X}{:02X}{:<08}{:02X}'.format(addr, f, l, '{:02X}'.format(mask_ch), id) chunk = bytes.fromhex(hex_chunk) data = chunk + crc16_calc(chunk) return data # addr = 12345678 # - сетевой адрес устройства (4байта) в формате BCD, старшим байтом вперёд f = 1 # - код функции запроса (1 байт) чтение текущих показаний l = 14 # - общая длина пакета (1 байт) mask_ch = 2 # – битовая маска запрашиваемых каналов (4 байта) (чтение второго канала) id = 24228 # - идентификатор запроса (любые 2 байта) # data = create_package(addr, f, l, mask_ch, id) # отправить теплосчетчику, # print(data) #b'\x124Vx\x01\x0e\x02\x00\x00\x00^\xa4Ac'
Офлайн
AkhepythonСначала формировать данные в hex. Потом передавать сформированные данные как байты простые. Потом получать ответ от устройства в виде простых байтов. Потом разбирать эти простые байты на поля и получать данные из этих полей.
Единственное пока, что понял из найденных примеров что нужно передавать данные в НЕХ.
Отредактировано py.user.next (Дек. 22, 2021 00:07:41)
Офлайн
Здравствуйте, увидел Ваше сообщения о созданию пакета данных с CRC. Не могли бы Вы помочь в разборе пакета приходящего от счетчика?
Счетчик Пульсар с rs485. Запрос “08 56 16 18 01 0E 03 00 00 00 01 00 FE 71”.
Получаю ответ: “085616180112a3e8103c0000000001005fab”.
Вручную (согласно протокола от Пульсар) разбираю: “08561618” - ADDR (номер счетчика), “01” - код функции запроса, “12” - общая длина пакета, “a3e8103c00000000” - данные, “01 00” - ID (идентификатор запроса (любые 2 байта))
“5fab” - CRC16.
Но как это сделать на Python? Просьба помочь!
Отредактировано Demion (Окт. 24, 2024 16:26:42)
Прикреплённый файлы:
_Для_форума_1.pdf (811,6 KБ)
Офлайн
> Но как это сделать на Python? Просьба помочь!
Что тебе нужно сделать? CRC16 вычислить? Но в твоём протоколе есть же готовый пример его вычисления…
Офлайн
Мне нужна помощь в написании кода на питоне для разбора ответа от прибора, например: ответ: “085616180112a3e8103c0000000001005fab”. Но ответ может быть и другой.
Офлайн
DemionМожешь составить кортеж из частей:
Здравствуйте, увидел Ваше сообщения о созданию пакета данных с CRC. Не могли бы Вы помочь в разборе пакета приходящего от счетчика?
Счетчик Пульсар с rs485. Запрос “08 56 16 18 01 0E 03 00 00 00 01 00 FE 71”.
Получаю ответ: “085616180112a3e8103c0000000001005fab”.
Вручную (согласно протокола от Пульсар) разбираю: “08561618” - ADDR (номер счетчика), “01” - код функции запроса, “12” - общая длина пакета, “a3e8103c00000000” - данные, “01 00” - ID (идентификатор запроса (любые 2 байта))
“5fab” - CRC16.
Но как это сделать на Python? Просьба помочь!
>>> def get_data(): ... text = '085616180112a3e8103c0000000001005fab' ... out = bytes.fromhex(text) ... return out ... >>> def parse_data(data): ... addr = data[:4] ... func = data[4:5] ... code = data[5:6] ... payload = data[6:-4] ... ident = data[-4:-2] ... crc = data[-2:] ... out = ( ... addr, ... func, ... code, ... payload, ... ident, ... crc ... ) ... return out ... >>> data = get_data() >>> >>> data_parsed = parse_data(data) >>> print(data_parsed) (b'\x08V\x16\x18', b'\x01', b'\x12', b'\xa3\xe8\x10<\x00\x00\x00\x00', b'\x01\x00', b'_\xab') >>> >>> print(list(data_parsed[0])) [8, 86, 22, 24] >>> print(list(data_parsed[1])) [1] >>> print(list(data_parsed[2])) [18] >>> print(list(data_parsed[3])) [163, 232, 16, 60, 0, 0, 0, 0] >>> print(list(data_parsed[4])) [1, 0] >>> print(list(data_parsed[5])) [95, 171] >>>
>>> def get_data(): ... text = '085616180112a3e8103c0000000001005fab' ... out = bytes.fromhex(text) ... return out ... >>> def parse_data(data): ... addr = data[:4] ... func = data[4:5] ... code = data[5:6] ... payload = data[6:-4] ... ident = data[-4:-2] ... crc16 = data[-2:] ... out = { ... 'address': addr, ... 'function': func, ... 'code': code, ... 'payload': payload, ... 'id': ident, ... 'crc': crc16 ... } ... return out ... >>> data = get_data() >>> >>> data_parsed = parse_data(data) >>> print(data_parsed) {'address': b'\x08V\x16\x18', 'function': b'\x01', 'code': b'\x12', 'payload': b'\xa3\xe8\x10<\x00\x00\x00\x00', 'id': b'\x01\x00', 'crc': b'_\xab'} >>> >>> print(list(data_parsed['address'])) [8, 86, 22, 24] >>> print(list(data_parsed['function'])) [1] >>> print(list(data_parsed['code'])) [18] >>> print(list(data_parsed['payload'])) [163, 232, 16, 60, 0, 0, 0, 0] >>> print(list(data_parsed['id'])) [1, 0] >>> print(list(data_parsed['crc'])) [95, 171] >>>
>>> class Data: ... def __init__(self, addr, func, code, ... payload, ident, crc16): ... self._addr = addr ... self._func = func ... self._code = code ... self._payload = payload ... self._ident = ident ... self._crc16 = crc16 ... def __str__(self): ... t = (self._addr, self._func, self._code, ... self._payload, self._ident, self._crc16) ... return '{}{}'.format(__class__.__name__, t) ... def addr(self): ... return self._addr ... def func(self): ... return self._func ... def code(self): ... return self._code ... def payload(self): ... return self._payload ... def ident(self): ... return self._ident ... def crc16(self): ... return self._crc16 ... >>> def get_data(): ... text = '085616180112a3e8103c0000000001005fab' ... out = bytes.fromhex(text) ... return out ... >>> def parse_data(data): ... addr = data[:4] ... func = data[4:5] ... code = data[5:6] ... payload = data[6:-4] ... ident = data[-4:-2] ... crc16 = data[-2:] ... out = Data( ... addr, ... func, ... code, ... payload, ... ident, ... crc16 ... ) ... return out ... >>> data = get_data() >>> >>> data_parsed = parse_data(data) >>> print(data_parsed) Data(b'\x08V\x16\x18', b'\x01', b'\x12', b'\xa3\xe8\x10<\x00\x00\x00\x00', b'\x01\x00', b'_\xab') >>> >>> print(list(data_parsed.addr())) [8, 86, 22, 24] >>> print(list(data_parsed.func())) [1] >>> print(list(data_parsed.code())) [18] >>> print(list(data_parsed.payload())) [163, 232, 16, 60, 0, 0, 0, 0] >>> print(list(data_parsed.ident())) [1, 0] >>> print(list(data_parsed.crc16())) [95, 171] >>>
>>> data = bytes([0x01, 0x02, 0x03]) >>> data b'\x01\x02\x03' >>> >>> data[1] 2 >>> >>> data[1] = 4 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'bytes' object does not support item assignment >>>
>>> data = bytearray([0x01, 0x02, 0x03]) >>> data bytearray(b'\x01\x02\x03') >>> >>> data[1] 2 >>> >>> data[1] = 4 >>> data bytearray(b'\x01\x04\x03') >>> >>> data[1] 4 >>>
Отредактировано py.user.next (Окт. 27, 2024 23:05:45)
Офлайн
Demion
Мне нужна помощь в написании кода на питоне для разбора ответа от прибора, например: ответ: “085616180112a3e8103c0000000001005fab”. Но ответ может быть и другой.
import struct def calculate_crc16_modbus(data): crc = 0xFFFF for byte in data: crc ^= byte for _ in range(8): if (crc & 0x0001): crc = (crc >> 1) ^ 0xA001 else: crc >>= 1 return crc.to_bytes(2, byteorder='little') def parse(data): hex_data = bytes.fromhex(data) addr = hex_data[:4] f = hex_data[4] l = hex_data[5] ch = hex_data[6:-4] id = hex_data[-4:-2] crc = hex_data[-2:] if crc != calculate_crc16_modbus(hex_data[:-2]): print('bad data') return None out = {} out['addr'] = ''.join(f'{byte >> 4}{byte & 0x0F}' for byte in addr) out['func'] = int(f) out['len'] = int(l) out['value'] = out['func'] == 1 and struct.unpack('ff', ch)[0] or None out['id'] = id.hex() return out data = parse('085616180112a3e8103c0000000001005fab') print(f"addr: {data['addr']}") print(f"func_num: {data['func']}") print(f"byte_received: {data['len']}") print(f"value: {data['value']}") print(f"id: {data['id']}")
Офлайн