Python, using variables in pymodbus.utilities.computeCRC - crc

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

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

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

Related

How to get output from a function called inside apply_sync in python2?

Using ipyparallel and python2 I am starting an ipcontroller and a single ipengine (both with --debug). In that engine I run code like follows:
import ipyparallel as ipp
def foo():
import sys
print("This is test 42")
sys.stdout.flush()
return 42
rc = ipp.Client()
rc[:].apply_sync(foo)
I get the expected output [42] but nowhere I see the print output
This is test 42
Where is that output? How to get that output?
You can get the output, but this is NOT properly documented. It is stored in some metadata dict returned with the results.
Here is what you have to do:
results = rc[:].apply_sync(foo)
for metadata in result.metadata:
print(metadata['stdout'])

How To read/iterate through a Datastream in Python

I have a stream created at port 9999 of my computer.
I have to implement DGIM Algorithm on it.
However I am not able to read the bits in the Data stream one by one.
Below is my code:
from pyspark import SparkContext
from pyspark.streaming import StreamingContext
import math
sc = SparkContext("local[2]", "NetworkWordCount")
ssc = StreamingContext(sc, 1)
when I use the following command I am able to print the stream in batches:
lines.pprint()
ssc.start() # Start the computation
ssc.awaitTermination()
But when I try to print each bit it gives an error:
for l in lines.iter_lines():
print l
ssc.start() # Start the computation
ssc.awaitTermination()
Can someone tell me how can I read each bit from the stream so that I could
implement the algorithm on it?
I used the following code:
streams.foreachRDD(lambda c: function(c))
function(c):
c.collect()
This makes an rdd out of each stream and the function collects all the streams

Python 2 and 3 differences in hashing a uuid

I have some py2 code that works in python 2:
import uuid
import hashlib
playername = "OfflinePlayer:%s" % name # name is just a text only username
m = hashlib.md5()
m.update(playername)
d = bytearray(m.digest())
d[6] &= 0x0f
d[6] |= 0x30
d[8] &= 0x3f
d[8] |= 0x80
print(uuid.UUID(bytes=str(d)))
However, when the code when run in python3, it produces "TypeError: Unicode-objects must be encoded before hashing" when m.update() is attempted. I tried to endcode it first with the default utf-8 by:
m.update(playername.encode())
but now this line -
print(uuid.UUID(bytes=str(d)))
produces this error:
File "/usr/lib/python3.5/uuid.py", line 149, in __init__
raise ValueError('bytes is not a 16-char string')
ValueError: bytes is not a 16-char string
I then tried to decode it back, but the bitwise operations have evidently ruined it (I am guessing?):
print(uuid.UUID(bytes=(d.decode())))
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfd in position 2: invalid start byte
I don't honestly know what the purpose of the bitwise operations is in the "big-picture". The code snippet in general is supposed to produce the same expected UUID every time based on the spelling of the username.
I just want this code to do the same job in Python3 that it did in Python 2 :(
Thanks in advance.
A couple of things:
m.update(playername.encode('utf-8'))
Should properly encode your string.
print(uuid.UUID(bytes=bytes(d)))
Should return the UUID properly.
Example:
https://repl.it/EyuG/0

Python 2.7 + Raspberry Pi 3 + UART (Serial)

some trouble with Python on RPi3 over UART.
My Python 2.7 script:
import time
import serial
ser = serial.Serial(
port='/dev/ttyS0',
baudrate=115200,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1
)
while 1:
ser.write('hello')
time.sleep(1)
And output in terminal is:
hellohello`??p?nnn?`??p?nnn?`??p?nnn?`??p?nnn?`??p?nnn?`??p?nnn?`??p?nnn?
Sometimes is "hello" two times, sometimes five times.
Standars RPi3 console output is off (in raspi-config). UART converter is 3V3 logic.
Could you help me? Thanx a lot!
Waldi

Python3 Bytestreams and UDP

I'm trying to send a packet that needs to arrive at its destination as hex in the form:
01 02 a1 a2 b1 b2
In Python2, the UDP method to send that would be:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.send(message, (UDP_IP, UDP_Port))
Message could be passed a hex string like:
\x01\x02\xa1\xa2\xb1\xb2 and that would arrive in the correct format.
In Python3, I cannot pass message the same value without getting the error str does not support the buffer interface. The problem then being is that if I pass message a bytestream b'\x01\x02\xa1\xa2\xb1\xb2' It will not arrive in the correct format.
Has anyone got any suggestions (other than port to 2.7)?
#!/usr/bin/python3
#Import block
import gzip, zlib
import time
import binascii
import struct
import socket
#Start of code
def compress():
"""The function to compress the packet"""
with open('results/file', 'r') as f:
'''Open the file with all the stuff in'''
for lines in f.readlines():
'''Each line represents one packet that will be sent'''
lines = (lines.strip("\n")) #Make sure their are no stray new lines
lines = lines.encode('UTF-8') #Encode for compression
compressed = gzip.compress(lines, 6)
pureHex = (binascii.hexlify(compressed))
return pureHex
def generator(pureHex):
"""The function to add the additional information to the packet"""
packet = [pureHex[i:i+2] for i in range(0, len(pureHex), 2)]
packet = b'\\x' + b'\\x'.join(packet) #Add the \\x that's needed
packet = packet.decode('UTF-8') #Requires decoding to remove the silly second \ that you have to add
return packet
def post(packet):
"""The function to post/send the message via UDP"""
sock.sendto(packet, (UDP_IP, UDP_PORT))
if __name__ == '__main__':
sock = socket.socket(socket.AF_INET,
socket.SOCK_DGRAM)
UDP_IP = "101.101.101.101" #Target IP Address
UDP_PORT = 5010 #Target Port Number
pureHex = compress()
packet = generator(pureHex)
post(packet)
You should send compressed directly and drop all other code that converts bytes to a hex string only to try to convert it back using an pseudo-emulation of Python representation for bytestrings.
Learn how bytes differ from their hex representation in Python source code:
>>> import binascii
>>> b = binascii.unhexlify('0102') # hex string to bytes
>>> b
b'\x01\x02' # representation: repr(b)
>>> len(_)
2
>>> b'\\x01\\x02' #XXX it is not what you want
b'\\x01\\x02'
>>> len(_)
8
>>> repr(b)
"b'\\x01\\x02'" # repr of a repr
>>> repr(repr(b))
'"b\'\\\\x01\\\\x02\'"' # repr of a repr of a repr
You need encode the packet. Change the line:
post(packet)
to:
post(bytes(packet,"utf-8"))
This worked for me.