1

I am searching for days, if I used the wrong search strings, I am sorry.

I want to use "pymodbus.utilities.computeCRC" to calculate the CRC value to communicate with a Modbus device that uses proprietary code, so no default "read register" functions can be used.

Correct CRC is 0x34bb

The problem is, that it only works with version 1, give the hex values direct to computeCRC, but none of the "variable" options are working.

import pymodbus.utilities
meins=[]
meins.append('10')
meins.append('33')
meins.append('01')
meins.append('01')

meins1=''
for i in meins:
        meins1 = meins1 + "\\x" + i

meins2='\x10\x33\x01\x01'

meins3=bytearray.fromhex("10330101")

crc=hex(pymodbus.utilities.computeCRC('\x10\x33\x01\x01'))
print(crc)
crc=hex(pymodbus.utilities.computeCRC(meins))
print(crc)
crc=hex(pymodbus.utilities.computeCRC(meins1))
print(crc)
crc=hex(pymodbus.utilities.computeCRC(meins2))
print(crc)
crc=hex(pymodbus.utilities.computeCRC(meins3))
print(crc)

Output:

  • 0x34bb
  • 0x2a9c
  • 0xdc0b
  • 0x9c0a
  • 0x5dca
Sanju
  • 1,974
  • 1
  • 18
  • 33
dakoal
  • 13
  • 2
  • what version of pymodbus and python are you running this snippet on ? – Sanju Oct 20 '17 at 07:07
  • Please check if you are providing a correct piece of code, The reason being the output for `crc=hex(pymodbus.utilities.computeCRC('\x10\x33\x01\x01'))` and `crc=hex(pymodbus.utilities.computeCRC(meins2))` should be same (`0x34bb`) but in your question the response for the latter is provided as `0x9c0a`. – Sanju Oct 20 '17 at 07:15

2 Answers2

0

Here is how you can use the CRC generator for your need , There is a subtle difference on how to the input needs to be passed depending on the python version (2.7 or 3.x).

Python3 and Pymodbus==1.3.2

Note python3 and pymodbus requires bytestrings to generate CRC .

import pymodbus.utilities
from pymodbus.compat import int2byte
meins=[]
meins.append(0x10)
meins.append(0x33)
meins.append(0x01)
meins.append(0x01)

meins1=b''
for i in meins:
    meins1 = meins1 + int2byte(i)

meins2=b'\x10\x33\x01\x01'

meins3=bytearray.fromhex("10330101")

crc=hex(pymodbus.utilities.computeCRC(b'\x10\x33\x01\x01'))
print(crc)
crc=hex(pymodbus.utilities.computeCRC(meins))
print(crc)
crc=hex(pymodbus.utilities.computeCRC(meins1))
print(crc)
crc=hex(pymodbus.utilities.computeCRC(meins2))
print(crc)
crc=hex(pymodbus.utilities.computeCRC(meins3))
print(crc)

Output

0x34bb
0x34bb
0x34bb
0x34bb
0x34bb

Python2 and pymodbus==1.3.2

import pymodbus.utilities
from pymodbus.compat import int2byte
meins=[]
meins.append(int2byte(0x10))
meins.append(int2byte(0x33))
meins.append(int2byte(0x1))
meins.append(int2byte(0x1))

meins1=''
for i in meins:
        meins1 = meins1 + i

meins2='\x10\x33\x01\x01'

meins3=bytearray.fromhex("10330101")
meins3=''.join(str(meins3))

crc=hex(pymodbus.utilities.computeCRC('\x10\x33\x01\x01'))
print(crc)
crc=hex(pymodbus.utilities.computeCRC(meins))
print(crc)
crc=hex(pymodbus.utilities.computeCRC(meins1))
print(crc)
crc=hex(pymodbus.utilities.computeCRC(meins2))
print(crc)
crc=hex(pymodbus.utilities.computeCRC(meins3))
print(crc)

Output

0x34bb
0x34bb
0x34bb
0x34bb
0x34bb
Sanju
  • 1,974
  • 1
  • 18
  • 33
  • Hi, thank you for the answer. Python 2.7 it is. Yes, with your modifications it works now like a charme. – dakoal Oct 20 '17 at 09:30
0

For Information, here the "ugly python beginner" version of my request to the device. In this case the request sets the output wattage of a battery inverter to 50 Watts. The value is stored correctly in the device.

Code

import minimalmodbus
import struct
import sys
import string
import serial
import pymodbus.payload
import time

#Wattage to program to the modbus device in hex format
watt = '{0:04X}'.format(50)

#combine the wattage to the rest of the string
string='103F0D'+watt+'01AE01F400960000000000'

#convert to a format computeCRC can work with
stringh=bytearray.fromhex(string)
stringh=''.join(str(stringh))
crc=pymodbus.utilities.computeCRC(stringh)

#convert crc to HEX String
crc='{0:04X}'.format(crc)

#combine Payload with CRC
string=string+crc

#debug:
#print(string)

#convert to a Format ser.write can send
stringh=bytearray.fromhex(string)
stringh=''.join(str(stringh))

ser = serial.Serial('/dev/ttyUSB0', 57600)
ser.write(stringh)
time.sleep(0.1)
anz=ser.inWaiting()
str=ser.read(anz)
for char in str:
               mm = int(char.encode('hex'), 16)
               print(hex(mm))
# Wait for inverter to accept command
time.sleep(1)
# Status 3E
# Send Status check command
ser.write("\x10\x3E\x01\x01\xA5\x78")
# wait for answer
time.sleep(0.1)
# how many bytes came back
anz=ser.inWaiting()
# read all bytes
str=ser.read(anz)
# extract the 2 bytes with the current load setting
str1=str[13]+str[14]
# convert
p=int(str1.encode('hex'), 16) / 10
print(p)

Output

0x10
0x3f
0x1
0x1
0xf4
0xb8

50

The Bytes are

  • 0x10 - Device address
  • 0x3F - Command we sent before
  • 0x1 0x1 - Command accepted
  • 0xf4 0xb8 - CRC

    50 - Value read from device

dakoal
  • 13
  • 2
  • You are using two modbus libraries and yet you chose to send the raw packet over serial line ? Why can't you just use the library api's which should remove most of the overheads you need to do it yourself. – Sanju Oct 21 '17 at 05:32
  • The modbus libraries are for other devices, also driven from here. The one device in this Special case doesn't use Registers. It has it's own proprietary implementation. Believe me, I tried to use the Default Tools. – dakoal Oct 22 '17 at 08:10