Util

This module contains utility functions for working with PLC DB objects. There are functions to work with the raw bytearray data snap7 functions return In order to work with this data you need to make python able to work with the PLC bytearray data.

For example code see test_util.py and example.py in the example folder.

example:

spec/DB layout

# Byte index    Variable name  Datatype
layout="""
4             ID             INT
6             NAME           STRING[6]

12.0          testbool1      BOOL
12.1          testbool2      BOOL
12.2          testbool3      BOOL
12.3          testbool4      BOOL
12.4          testbool5      BOOL
12.5          testbool6      BOOL
12.6          testbool7      BOOL
12.7          testbool8      BOOL
13            testReal       REAL
17            testDword      DWORD
"""

client = snap7.client.Client()
client.connect('192.168.200.24', 0, 3)

# this looks confusing but this means uploading from the PLC to YOU
# so downloading in the PC world :)

all_data = client.upload(db_number)

simple:

db1 = snap7.util.DB(
    db_number,              # the db we use
    all_data,               # bytearray from the plc
    layout,                 # layout specification DB variable data
                            # A DB specification is the specification of a
                            # DB object in the PLC you can find it using
                            # the dataview option on a DB object in PCS7

    17+2,                   # size of the specification 17 is start
                            # of last value
                            # which is a DWORD which is 2 bytes,

    1,                      # number of row's / specifications

    id_field='ID',          # field we can use to identify a row.
                            # default index is used
    layout_offset=4,        # sometimes specification does not start a 0
                            # like in our example
    db_offset=0             # At which point in 'all_data' should we start
                            # reading. if could be that the specification
                            # does not start at 0
)

Now we can use db1 in python as a dict. if 'ID' contains
the 'test' we can identify the 'test' row in the all_data bytearray

To test of you layout matches the data from the plc you can
just print db1[0] or db['test'] in the example

db1['test']['testbool1'] = 0

If we do not specify a id_field this should work to read out the
same data.

db1[0]['testbool1']

to read and write a single Row from the plc. takes like 5ms!

db1['test'].write()

db1['test'].read(client)
class snap7.util.DB(db_number: int, bytearray_: bytearray, specification: str, row_size: int, size: int, id_field: Optional[str] = None, db_offset: Optional[int] = 0, layout_offset: Optional[int] = 0, row_offset: Optional[int] = 0, area: Optional[snap7.types.Areas] = <Areas.DB: 132>)[source]

Manage a DB bytearray block given a specification of the Layout.

It is possible to have many repetitive instances of a specification this is called a “row”.

Probably most usecases there is just one row

bytearray_

buffer data from the PLC.

specification

layout of the DB Rows.

row_size

bytes size of a db row.

layout_offset

at which byte in the row specificaion we start reading the data.

db_offset

at which byte in the db starts reading.

Examples

>>> db1[0]['testbool1'] = test
>>> db1.write()   # puts data in plc
__init__(db_number: int, bytearray_: bytearray, specification: str, row_size: int, size: int, id_field: Optional[str] = None, db_offset: Optional[int] = 0, layout_offset: Optional[int] = 0, row_offset: Optional[int] = 0, area: Optional[snap7.types.Areas] = <Areas.DB: 132>)[source]

Creates a new instance of the Row class.

Parameters:
  • db_number – number of the DB to read from. This value should be 0 if area!=Areas.DB.
  • bytearray – initial buffer read from the PLC.
  • specification – layout of the PLC memory.
  • row_size – bytes size of a db row.
  • size – lenght of the memory area.
  • id_field – name to reference the row. Optional.
  • db_offset – at which byte in the db starts reading.
  • layout_offset – at which byte in the row specificaion we start reading the data.
  • row_offset – offset between rows.
  • area – which memory area this row is representing.
make_rows()[source]

Make each row for the DB.

set_data(bytearray_: bytearray)[source]

Set the new buffer data from the PLC to the current instance.

Parameters:bytearray – buffer to save.
Raises:TypeError – if bytearray_ is not an instance of bytearray
class snap7.util.DB_Row(bytearray_: bytearray, _specification: str, row_size: Optional[int] = 0, db_offset: int = 0, layout_offset: int = 0, row_offset: Optional[int] = 0, area: Optional[snap7.types.Areas] = <Areas.DB: 132>)[source]

Provide ROW API for DB bytearray

bytearray_

reference to the data of the parent DB.

_specification

row specification layout.

__getitem__(key)[source]

Get a specific db field

__init__(bytearray_: bytearray, _specification: str, row_size: Optional[int] = 0, db_offset: int = 0, layout_offset: int = 0, row_offset: Optional[int] = 0, area: Optional[snap7.types.Areas] = <Areas.DB: 132>)[source]

Creates a new instance of the DB_Row class.

Parameters:
  • bytearray – reference to the data of the parent DB.
  • _specification – row specification layout.
  • row_size – Amount of bytes of the row.
  • db_offset – at which byte in the db starts reading.
  • layout_offset – at which byte in the row specificaion we start reading the data.
  • row_offset – offset between rows.
  • area – which memory area this row is representing.
Raises:

TypeError – if bytearray_ is not an instance of bytearray or DB.

export() → Dict[str, Union[str, int, float, bool, datetime.datetime]][source]

Export dictionary with values

Returns:dictionary containing the values of each value of the row.
get_bytearray() → bytearray[source]

Gets bytearray from self or DB parent

Returns:Buffer data corresponding to the row.
get_offset(byte_index: Union[str, int]) → int[source]
Calculate correct beginning position for a row
the db_offset = row_size * index
Parameters:byte_index – byte index from where to start reading from.
Returns:Amount of bytes to ignore.
get_value(byte_index: Union[str, int], type_: str) → Union[ValueError, int, float, str, datetime.datetime][source]

Gets the value for a specific type.

Parameters:
  • byte_index – byte index from where start reading.
  • type – type of data to read.
Raises:
  • Snap7Exception – if reading a string when checking the lenght of the string.
  • ValueError – if the type_ is not handled.
Returns:

Value read according to the type_

read(client: snap7.client.Client) → None[source]

Read current data of db row from plc.

Parameters:

clientClient snap7 instance.

Raises:
  • TypeError – if the _bytearray is not an instance of DB class.
  • ValueError – if the row_size is less than 0.
set_value(byte_index: Union[str, int], type: str, value: Union[bool, str, int, float]) → Optional[bytearray][source]

Sets the value for a specific type in the specified byte index.

Parameters:
  • byte_index – byte index to start writing to.
  • type – type of value to write.
  • value – value to write.
Raises:
  • Snap7Exception – if reading a string when checking the lenght of the string.
  • ValueError – if the type_ is not handled.
Returns:

Buffer data with the value written. Optional.

unchanged(bytearray_: bytearray) → bool[source]

Checks if the bytearray is the same

Parameters:bytearray – buffer of data to check.
Returns:True if the current bytearray_ is equal to the new one. Otherwise is False.
write(client: snap7.client.Client) → None[source]

Write current data to db in plc

Parameters:

clientClient snap7 instance.

Raises:
  • TypeError – if the _bytearray is not an instance of DB class.
  • ValueError – if the row_size is less than 0.
snap7.util.get_bool(bytearray_: bytearray, byte_index: int, bool_index: int) → bool[source]

Get the boolean value from location in bytearray

Parameters:
  • bytearray – buffer data.
  • byte_index – byte index to read from.
  • bool_index – bit index to read from.
Returns:

True if the bit is 1, else 0.

Examples

>>> buffer = bytearray([0b00000001])  # Only one byte length
>>> get_bool(buffer, 0, 0)  # The bit 0 starts at the right.
    True
snap7.util.get_byte(bytearray_: bytearray, byte_index: int) → int[source]

Get byte value from bytearray.

Notes

WORD 8bit 1bytes Decimal number unsigned B#(0) to B#(255) => 0 to 255

Parameters:
  • bytearray – buffer to be read from.
  • byte_index – byte index to be read.
Returns:

value get from the byte index.

snap7.util.get_dint(bytearray_: bytearray, byte_index: int) → int[source]

Get dint value from bytearray.

Notes

Datatype dint consists in 4 bytes in the PLC. Maximum possible value is 2147483647. Lower posible value is -2147483648.

Parameters:
  • bytearray – buffer to read.
  • byte_index – byte index from where to start reading.
Returns:

Value read.

Examples

>>> import struct
>>> data = bytearray(4)
>>> data[:] = struct.pack(">i", 2147483647)
>>> snap7.util.get_dint(data, 0)
    2147483647
snap7.util.get_dword(bytearray_: bytearray, byte_index: int) → int[source]

Gets the dword from the buffer.

Notes

Datatype dword consists in 8 bytes in the PLC. The maximum value posible is 4294967295

Parameters:
  • bytearray – buffer to read.
  • byte_index – byte index from where to start reading.
Returns:

Value read.

Examples

>>> data = bytearray(8)
>>> data[:] = b"\x12\x34\xAB\xCD"
>>> snap7.util.get_dword(data, 0)
    4294967295
snap7.util.get_int(bytearray_: bytearray, byte_index: int) → int[source]

Get int value from bytearray.

Notes

Datatype int in the PLC is represented in two bytes

Parameters:
  • bytearray – buffer to read from.
  • byte_index – byte index to start reading from.
Returns:

Value read.

Examples

>>> data = bytearray([0, 255])
>>> snap7.util.get_int(data, 0)
    255
snap7.util.get_real(bytearray_: bytearray, byte_index: int) → float[source]

Get real value.

Notes

Datatype real is represented in 4 bytes in the PLC. The packed representation uses the IEEE 754 binary32.

Parameters:
  • bytearray – buffer to read from.
  • byte_index – byte index to reading from.
Returns:

Real value.

Examples

>>> data = bytearray(b'B\xf6\xa4Z')
>>> snap7.util.get_real(data, 0)
    123.32099914550781
snap7.util.get_sint(bytearray_: bytearray, byte_index: int) → int[source]

Get the small int

Notes

Datatype sint (Small int) consists in 1 byte in the PLC. Maximum value posible is 127. Lowest value posible is -128.

Parameters:
  • bytearray – buffer to read from.
  • byte_index – byte index from where to start reading.
Returns:

Value read.

Examples

>>> data = bytearray([127])
>>> snap7.util.get_sint(data, 0)
    127
snap7.util.get_string(bytearray_: bytearray, byte_index: int, max_size: int) → str[source]

Parse string from bytearray

Notes

The first byte of the buffer will contain the max size posible for a string. The second byte contains the length of the string that contains.

Parameters:
  • bytearray – buffer from where to get the string.
  • byte_index – byte index from where to start reading.
  • max_size – maximum possible string size.
Returns:

String value.

Examples

>>> data = bytearray([254, len("hello world")] + [ord(letter) for letter in "hello world"])
>>> snap7.util.get_string(data, 0, 255)
'hello world'
snap7.util.get_usint(bytearray_: bytearray, byte_index: int) → int[source]

Get the unsigned small int from the bytearray

Notes

Datatype usint (Unsigned small int) consists on 1 byte in the PLC. Maximum posible value is 255. Lower posible value is 0.

Parameters:
  • bytearray – buffer to read from.
  • byte_index – byte index from where to start reading.
Returns:

Value read.

Examples

>>> data = bytearray([255])
>>> snap7.util.get_usint(data, 0)
    255
snap7.util.get_word(bytearray_: bytearray, byte_index: int) → int[source]

Get word value from bytearray.

Notes

WORD 16bit 2bytes Decimal number unsigned B#(0,0) to B#(255,255) => 0 to 65535

Parameters:
  • bytearray – buffer to get the word from.
  • byte_index – byte index from where start reading from.
Returns:

Word value.

Examples

>>> data = bytearray([0, 100])  # two bytes for a word
>>> snap7.util.get_word(data, 0)
    100
snap7.util.parse_specification(db_specification: str) → collections.OrderedDict[source]
Create a db specification derived from a
dataview of a db in which the byte layout is specified
Parameters:db_specification – string formatted table with the indexes, aliases and types.
Returns:Parsed DB specification.
snap7.util.set_bool(bytearray_: bytearray, byte_index: int, bool_index: int, value: bool)[source]

Set boolean value on location in bytearray.

Parameters:
  • bytearray – buffer to write to.
  • byte_index – byte index to write to.
  • bool_index – bit index to write to.
  • value – value to write.

Examples

>>> buffer = bytearray([0b00000000])
>>> set_bool(buffer, 0, 0, True)
>>> buffer
    bytearray(b"\x01")
snap7.util.set_byte(bytearray_: bytearray, byte_index: int, _int: int) → bytearray[source]

Set value in bytearray to byte

Parameters:
  • bytearray – buffer to write to.
  • byte_index – byte index to write.
  • _int – value to write.
Returns:

buffer with the written value.

Examples

>>> buffer = bytearray([0b00000000])
>>> set_byte(buffer, 0, 255)
    bytearray(b"\xFF")
snap7.util.set_dint(bytearray_: bytearray, byte_index: int, dint: int)[source]

Set value in bytearray to dint

Notes

Datatype dint consists in 4 bytes in the PLC. Maximum possible value is 2147483647. Lower posible value is -2147483648.

Parameters:
  • bytearray – buffer to write.
  • byte_index – byte index from where to start writing.

Examples

>>> data = bytearray(4)
>>> snap7.util.set_dint(data, 0, 2147483647)
>>> data
    bytearray(b'\x7f\xff\xff\xff')
snap7.util.set_dword(bytearray_: bytearray, byte_index: int, dword: int)[source]

Set a DWORD to the buffer.

Notes

Datatype dword consists in 8 bytes in the PLC. The maximum value posible is 4294967295

Parameters:
  • bytearray – buffer to write to.
  • byte_index – byte index from where to writing reading.
  • dword – value to write.

Examples

>>> data = bytearray(4)
>>> snap7.util.set_dword(data,0, 4294967295)
>>> data
    bytearray(b'\xff\xff\xff\xff')
snap7.util.set_int(bytearray_: bytearray, byte_index: int, _int: int)[source]

Set value in bytearray to int

Notes

An datatype int in the PLC consists of two bytes.

Parameters:
  • bytearray – buffer to write on.
  • byte_index – byte index to start writing from.
  • _int – int value to write.
Returns:

Buffer with the written value.

Examples

>>> data = bytearray(2)
>>> snap7.util.set_int(data, 0, 255)
    bytearray(b'\x00\xff')
snap7.util.set_real(bytearray_: bytearray, byte_index: int, real) → bytearray[source]

Set Real value

Notes

Datatype real is represented in 4 bytes in the PLC. The packed representation uses the IEEE 754 binary32.

Parameters:
  • bytearray – buffer to write to.
  • byte_index – byte index to start writing from.
  • real – value to be written.
Returns:

Buffer with the value written.

Examples

>>> data = bytearray(4)
>>> snap7.util.set_real(data, 0, 123.321)
    bytearray(b'B\xf6\xa4Z')
snap7.util.set_sint(bytearray_: bytearray, byte_index: int, _int) → bytearray[source]

Set small int to the buffer.

Notes

Datatype sint (Small int) consists in 1 byte in the PLC. Maximum value posible is 127. Lowest value posible is -128.

Parameters:bytearray

buffer to write to.

byte_index: byte index from where to start writing. _int: value to write.

Returns:Buffer with the written value.

Examples

>>> data = bytearray(1)
>>> snap7.util.set_sint(data, 0, 127)
    bytearray(b'\x7f')
snap7.util.set_string(bytearray_: bytearray, byte_index: int, value: str, max_size: int)[source]

Set string value

Parameters:
  • bytearray – buffer to write to.
  • byte_index – byte index to start writing from.
  • value – string to write.
  • max_size – maximum possible string size.
Raises:
  • TypeError – if the value is not a str.
  • ValueError – if the length of the value is larger than the max_size.

Examples

>>> data = bytearray(20)
>>> snap7.util.set_string(data, 0, "hello world", 255)
>>> data
    bytearray(b'\x00\x0bhello world\x00\x00\x00\x00\x00\x00\x00')
snap7.util.set_usint(bytearray_: bytearray, byte_index: int, _int: int) → bytearray[source]

set unsigned small int

Notes

Datatype usint (Unsigned small int) consists on 1 byte in the PLC. Maximum posible value is 255. Lower posible value is 0.

Parameters:bytearray

buffer to write.

byte_index: byte index from where to start writing. _int: value to write.

Returns:Buffer with the written value.

Examples

>>> data = bytearray(1)
>>> snap7.util.set_usint(data, 0, 255)
    bytearray(b'\xff')
snap7.util.set_word(bytearray_: bytearray, byte_index: int, _int: int)[source]

Set value in bytearray to word

Notes

Word datatype is 2 bytes long.

Parameters:
  • bytearray – buffer to be written.
  • byte_index – byte index to start write from.
  • _int – value to be write.
Returns:

buffer with the written value

snap7.util.utc2local(utc: Union[datetime.date, datetime.datetime]) → Union[datetime.datetime, datetime.date][source]

Returns the local datetime

Parameters:utc – UTC type date or datetime.
Returns:Local datetime.