gijzelaerr / python-snap7

A Python wrapper for the snap7 PLC communication library
http://python-snap7.readthedocs.org/
MIT License
643 stars 246 forks source link

STRING writing problems on PLC #424

Closed nikyred1978 closed 1 year ago

nikyred1978 commented 1 year ago

I have a problem, I have to write this string:('001;+293.50;+58.00;+150.00;+000.01;+003.14;+000.01;08;080;01;') on a DB32 in offset 0 format STRING[65], but when I run the code it transfers me this string:('1;+293.50;+58.00;+150.00;+000.01;+003.14;+000.01;' ), then it removes the first 2 zeros and also removes the last part of the string .

This is code, below:

`import snap7 from snap7.util import * import time

plc = snap7.client.Client()

try: plc.connect('128.0.0.1', 0, 1) except snap7.snap7exceptions.Snap7Exception as e: print("Error PLC:", e) exit()

data_str = '001;+293.50;+58.00;+150.00;+000.01;+003.14;+000.01;08;080;01;'

try: plc.db_write(34, 0, data_str) except snap7.snap7exceptions.Snap7Exception as e:
print('Error DB32:', e)

plc.disconnect()

`

nikteliy commented 1 year ago

Documentation says:

The Datatype STRING defines a string of maximal 254 characters. The field reserved for a standard string is 256 Bytes. This space is required in order to save 254 characters and a string-head of 2 bytes. The string-head contains the maximal and the actual length of the string. In a string all characters of the ASCII-Code can be used. A string can even contain special characters like control keys and non printable characters.

The first two bytes are consumed by the header. To avoid this, you can use helper functions from the Snap7 library: snap7.util.get_string and snap7.util.set_string, or you can write your own class to handle this data type, something like this:

import struct

class S7String:
    def __init__(self, value: str, max_length: int = 254) -> None:
        self.value = value
        self.max_length = max_length

    @classmethod
    def from_buffer(cls, buffer: bytes) -> str:
        max_length, actual_length = struct.unpack("!BB", buffer[:2])
        value = struct.unpack_from(f"{actual_length}s", buffer, 2)[0].decode()
        return cls(value=value, max_length=max_length)

    def to_buffer(self) -> bytearray:
        value = self.value.encode()
        actual_length = len(self.value)
        rest = (self.max_length - actual_length) * b"\x00"
        return struct.pack(f"BB{actual_length}s{len(rest)}s", self.max_length, actual_length, value, rest)

data_str = "001;+293.50;+58.00;+150.00;+000.01;+003.14;+000.01;08;080;01;"
s7_str = S7String(value=data_str, max_length=65)

client = snap7.client.Client()
client.connect('128.0.0.1', 0, 1)
client.db_write(db_number=34, start=0, data=s7_str.to_buffer())
buffer_rcv = client.db_read(db_number=34, start=0, size=65)
str_from_plc = S7String.from_buffer(buffer_rcv).value
assert data_str == str_from_plc
client.disconnect()

result: tia_portal_str

nikyred1978 commented 1 year ago

Fantastic! Thanks a lot, I've tried them all