Search code examples
pythonpython-3.xtcptelnetlib

unable to unpack information between custom Preamble in Python and telnetlib


I have an industrial sensor which provides me information via telnet over port 10001.

It has a Data Format as follows:

Table Data Format

Also the manual:

All the measuring values are transmitted int32 or uint32 or float depending on the sensors

Code

import telnetlib
import struct
import time

# IP Address, Port, timeout for Telnet
tn = telnetlib.Telnet("169.254.168.150", 10001, 10)


while True:
    op = tn.read_eager() # currently read information limit this till preamble
    print(op[::-1]) # make little-endian
    if not len(op[::-1]) == 0: # initially an empty bit starts (b'')
        data = struct.unpack('!4c', op[::-1]) # unpacking `MEAS`
    time.sleep(0.1)

my initial attempt:

  1. Connect to the sensor

  2. read data

  3. make it to little-endian

OUTPUT

b''
b'MEAS\x85\x8c\x8c\x07\xa7\x9d\x01\x0c\x15\x04\xf6MEAS'
b'\x04\xf6MEAS\x86\x8c\x8c\x07\xa7\x9e\x01\x0c\x15\x04\xf6'
b'\x15\x04\xf6MEAS\x85\x8c\x8c\x07\xa7\x9f\x01\x0c\x15'
b'\x15\x04\xf6MEAS\x87\x8c\x8c\x07\xa7\xa0\x01\x0c'
b'\xa7\xa2\x01\x0c\x15\x04\xf6MEAS\x87\x8c\x8c\x07\xa7\xa1\x01\x0c'
b'\x8c\x07\xa7\xa3\x01\x0c\x15\x04\xf6MEAS\x87\x8c\x8c\x07'
b'\x88\x8c\x8c\x07\xa7\xa4\x01\x0c\x15\x04\xf6MEAS\x88\x8c'
b'MEAS\x8b\x8c\x8c\x07\xa7\xa5\x01\x0c\x15\x04\xf6MEAS'
b'\x04\xf6MEAS\x8b\x8c\x8c\x07\xa7\xa6\x01\x0c\x15\x04\xf6'
b'\x15\x04\xf6MEAS\x8a\x8c\x8c\x07\xa7\xa7\x01\x0c\x15'
b'\x15\x04\xf6MEAS\x88\x8c\x8c\x07\xa7\xa8\x01\x0c'
b'\x01\x0c\x15\x04\xf6MEAS\x88\x8c\x8c\x07\xa7\xa9\x01\x0c'
b'\x8c\x07\xa7\xab\x01\x0c\x15\x04\xf6MEAS\x8b\x8c\x8c\x07\xa7\xaa'
b'\x8c\x8c\x07\xa7\xac\x01\x0c\x15\x04\xf6MEAS\x8c\x8c'
b'AS\x89\x8c\x8c\x07\xa7\xad\x01\x0c\x15\x04\xf6MEAS\x8a'
b'MEAS\x88\x8c\x8c\x07\xa7\xae\x01\x0c\x15\x04\xf6ME'
b'\x15\x04\xf6MEAS\x87\x8c\x8c\x07\xa7\xaf\x01\x0c\x15\x04\xf6'
b'\x15\x04\xf6MEAS\x8a\x8c\x8c\x07\xa7\xb0\x01\x0c'
b'\x0c\x15\x04\xf6MEAS\x8a\x8c\x8c\x07\xa7\xb1\x01\x0c'
b'\x07\xa7\xb3\x01\x0c\x15\x04\xf6MEAS\x89\x8c\x8c\x07\xa7\xb2\x01'
b'\x8c\x8c\x07\xa7\xb4\x01\x0c\x15\x04\xf6MEAS\x89\x8c\x8c'
b'\x85\x8c\x8c\x07\xa7\xb5\x01\x0c\x15\x04\xf6MEAS\x84'
b'MEAS\x87\x8c\x8c\x07\xa7\xb6\x01\x0c\x15\x04\xf6MEAS'
b'\x04\xf6MEAS\x8b\x8c\x8c\x07\xa7\xb7\x01\x0c\x15\x04\xf6'
b'\x15\x04\xf6MEAS\x8b\x8c\x8c\x07\xa7\xb8\x01\x0c\x15'
b'\x15\x04\xf6MEAS\x8a\x8c\x8c\x07\xa7\xb9\x01\x0c'
b'\xa7\xbb\x01\x0c\x15\x04\xf6MEAS\x87\x8c\x8c\x07\xa7\xba\x01\x0c'
  1. try to unpack the preamble !?

How do I read information like Article number, Serial number, Channel, Status, Measuring Value between the preamble?

The payload size seems to be fixed here for 22 Bytes (via Wireshark)

Wireshark Picture


Solution

  • I managed to avoid TelnetLib altogether and created a tcp client using python3. I had the payload size already from my wireshark dump (22 Bytes) hence I keep receiving 22 bytes of Information. Apparently the module sends two distinct 22 Bytes payload

    1. First (frame) payload has the preamble, serial, article, channel information
    2. Second (frame) payload has the information like bytes per frame, measuring value counter, measuring value Channel 1, measuring value Channel 2, measuring value Channel 3

    The information is in int32 and thus needs a formula to be converted to real readings (mentioned in the instruction manual)

    (as mentioned by @J_H the unpacking was as He mentioned in his answer with small changes)

    Code

    import socket
    import time
    import struct
    
    DRANGEMIN = 3261
    DRANGEMAX = 15853
    MEASRANGE = 50
    OFFSET = 35
    
    # Create a TCP/IP socket
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    server_address = ('169.254.168.150', 10001)
    print('connecting to %s port %s' % server_address)
    sock.connect(server_address)
    
    
    def value_mm(raw_val):
    
        return (((raw_val - DRANGEMIN) * MEASRANGE) / (DRANGEMAX - DRANGEMIN) + OFFSET)
    
    
    if __name__ == '__main__':
        while True:
            Laser_Value = 0
            data = sock.recv(22)
            preamble, article, serial, x1, x2 = struct.unpack('<4sIIQH', data)
            if not preamble == b'SAEM':
                status, bpf, mValCounter, CH1, CH2, CH3 = struct.unpack('<hIIIII',data)
                #print(CH1, CH2, CH3)
                Laser_Value = CH3
                print(str(value_mm(Laser_Value)) + " mm")
    
            #print('RAW: ' + str(len(data)))
            print('\n')
            #time.sleep(0.1)
    

    Sure enough, this provides me the information that is needed and I compared the information via the propreitary software which the company provides.