0

Read Serial

Using PySerial the following program was created:

import serial


class comunicacao():
    def __init__(self, porta, baud):
        s = serial.Serial(porta, baud)
        data = s.read(18)
        data = data
        print("Data: ", (data))

comunicacao('COM7', 57600)

It is receiving the number 10000 in decimal for tests, and the print output is: Data: b'\x020000000000002710\x03'

Because 2710 in HEX is 10000 in DEC.

Conversion

So trying to convert with the following ways:

  • print("Data: ", int(data, 16)) gives teh error:

print("Data: ", int(data, 16))

ValueError: invalid literal for int() with base 16: b'\x020000000000002710\x03'

  • With data = s.read(18).decode() the print output is Data: 0000000000002710 and trying to convert with int() gives the error:

print("Data: ", int(data, 16))

ValueError: invalid literal for int() with base 16: '\x020000000000002710\x03'

  • data = data.lstrip("0") with data = s.read(18).decode() didn't strip the leading zeroes.
  • And data = data.lstrip("0") with data = s.read(18) gives the error:

print("Data: ", (data.lstrip("0")))

TypeError: a bytes-like object is required, not 'str'

Question

How to convert this data type (I think it is as ASCII, but is a HEX number) to DEC?

Community
  • 1
  • 1
danieltakeshi
  • 887
  • 9
  • 37
  • 2
    Is something like `int(data[1:-1], 16)` sufficient for your case? – Jon Clements Aug 17 '18 at 12:22
  • Like a charm! Could you please explain it? With an answer, then i can accept. – danieltakeshi Aug 17 '18 at 12:22
  • 1
    I imagine the proper way to do it is that `\x02` might be an indicator that the next block of N bytes is a hex repr of an int (16 chars in this case) to make it more robust... It's called slicing - it's worth checking out: https://stackoverflow.com/questions/509211/understanding-pythons-slice-notation – Jon Clements Aug 17 '18 at 12:25
  • Yes, And if it receives a String, it will have to recognize it and don't convert. The program needs lots of improvement. But is evolving. Thanks for the tips – danieltakeshi Aug 17 '18 at 12:34
  • 1
    You might also want to look at the builtin `struct` module - it may/may not be useful for what you're doing here... – Jon Clements Aug 17 '18 at 12:36
  • 1
    Yeah, I also recommend the struct or array module if you can send binary representation of the data from the other end. Much more robust and a nicer protocol to handle. – Dalen Aug 17 '18 at 12:59

1 Answers1

1

What about this:

data = '\x020000000000002710\x03'
# If we say that "\x02" opens an hexadecimal representation of an integer,
# and that "\x03" ends it, then for any number of ints in hex form in data, do:
converted = [int(x, 16) for x in data.replace("\x02", "").split("\x03") if x]
print(converted)
print(converted[0])

You get the list of all numbers you read from the port. What this code does is that it removes the \x02 character so not to confuse the int() and then splits data by \x03. Then it converts each element using the int(x, 16). Using the classic way with added try statement would be more robust, if you expect some other data to be mixed in:

converted = []
for x in data.replace("\x02", "").split("\x03"):
    try:
        converted.append(int(x, 16))
    except: pass

If "\x03" is not the int separator, you can use \x02 as one and combine the slicing to extract the number of needed digits.

If "\x03" is still the hexnum terminator, but the numbers do not follow eachother then use something like this:

data = '\x020000000000002710\x03blahblah\x0200ff\x03mmmm'
converted = []
for x in data.split("\x02"):
    end = x.find("\x03")
    if end==-1: continue
    x = x[:end]
    try:
        converted.append(int(x, 16))
    except: pass

Printing the converted now will give you the list:

[10000, 255]

As you can see, this will work even if hex numbers aren't equally padded with zeroes. You can get the nice and reliablecode playing with similar code formulations.

Dalen
  • 4,128
  • 1
  • 17
  • 35
  • Yeah. Also, If i change the code to: `data = s.read()` I'll receive byte by byte and can group the data between STX (`\x02`) and ETX (`\x03`). Nice tip, I can use the way you told with a data of multiple data if I know the quantity of bytes and change `data = s.read(36)` for two packages of data. Will make some tests. – danieltakeshi Aug 17 '18 at 13:22
  • 1
    OK, but if you do s.read() make sure that the timeout is set, otherwise you might end waiting for the data indefinitely. – Dalen Aug 17 '18 at 13:28