python-snap7 Documentation

repository·master·Indexed 21 days ago

https://github.com/gijzelaerr/python-snap7

A pure Python S7 communication library for Siemens PLCs. It provides support for the classic S7 protocol (S7-300/400 and PUT/GET on S7-1200/1500) via the `s7` package, and the S7CommPlus protocol (S7-1200/1500) via the `s7commplus` package. Features include synchronous and asynchronous clients, TLS support for S7-1500 V2, symbolic tag access with PLC4X and nodeS7 dialects, and an experimental read optimizer to reduce network round-trips.

Tokens
25K
Snippets
88
Records
130
Agent score
73%

What's inside python-snap7

  1. Use the snap7.datatypes module for S7 data types and address encoding

    master
    The snap7.datatypes module provides the necessary definitions for S7 data types and utilities for address encoding. Use this module when you need to work with specific S7 data structures or when you need to calculate/encode addresses for reading and writing data to a PLC.
  2. Use the s7 CLI to interact with PLCs

    master

    The s7 command provides several subcommands for interacting with Siemens S7 PLCs:

    • server: Start an emulated S7 PLC server.
    • demo: Start a live S7 server that exposes real host metrics on DB1 (requires pip install "python-snap7[demo]").
    • read: Read data from a PLC.
    • write: Write data to a PLC.
    • dump: Dump DB contents.
    • info: Get PLC information.
    • discover: Discover devices on the network (optional subcommand).

    Use the -v or --verbose flag to enable debug output.

    s7 --help
  3. Choose between s7commplus and s7 client packages

    master

    python-snap7 provides two distinct client packages depending on your PLC hardware and protocol requirements:

    • s7commplus: Use this for the S7CommPlus protocol, which is required for S7-1200 and S7-1500 PLCs.
    • s7 (legacy): Use this for the classic S7 protocol, which supports S7-300/400 PLCs and PUT/GET access on S7-1200/1500.
  4. Understand S7 communication protocols and security

    master

    Siemens PLCs use different protocols depending on the hardware and firmware. python-snap7 implements the classic S7 protocol and S7CommPlus (V1, V2, and V3).

    ProtocolEncryptionAuthenticationUsed by
    S7 (classic)NoneNoneS7-300, S7-400, S7-1200, S7-1500 (PUT/GET mode)
    S7CommPlus V1NoneChallenge-responseS7-1200 FW 4+, S7-1500 FW 1.x
    S7CommPlus V2TLS 1.3Challenge-response + TLSS7-1500 FW 2.x
    S7CommPlus V3TLSCertificate-basedS7-1500 FW 3.x+

    Note: S7CommPlus V4 is not yet supported. If your PLC requires V4, consider using OPC UA.

  5. Understand byte_index relativity in s7.util

    master

    When using s7.util getter or setter functions (like get_bool, get_byte, etc.), the byte_index parameter is relative to the returned bytearray, not the absolute PLC address.

    If you read 1 byte from PLC offset 10, the resulting data object's index 0 corresponds to PLC offset 10.

    # To read DB1.DBX10.3:
    data = client.db_read(1, 10, 1)  # Read 1 byte starting at offset 10
    from s7.util import get_bool
    value = get_bool(data, 0, 3)  # byte_index=0, NOT 10
  6. Access Optimized Blocks using S7CommPlus

    master

    S7-1200/1500 Data Blocks with "Optimized block access" enabled do not use fixed byte offsets. Standard addresses like DB1.DBX0.0 are unreliable for these blocks.

    Instead, you must use symbolic (LID-based) access. This involves:

    1. Discovering LIDs (Logical IDs) via s7commplus.client.S7CommPlusClient.browse.
    2. Creating a Tag using Tag.from_access_string with the discovered LID.
    3. Using the Client to read/write the tag.

    Warning: Symbolic (LID-based) access is currently experimental and requires real PLC testing. The implementation follows the S7CommPlusDriver reference but has not been validated against hardware.

    from s7commplus import Client
    from s7.tags import Tag
    
    client = Client()
    client.connect("192.168.1.10")
    
    # Create a symbolic tag (LIDs come from browse)
    tag = Tag.from_access_string(
        "8A0E0001.A",           # DB1, LID 0xA
        datatype="REAL",
        name="Motor.Speed",
        symbol_crc=0x12345678,  # optional layout version check
    )
    
    # Read/write via S7CommPlus symbolic access
    speed = client.read_tag(tag)
    client.write_tag(tag, 1500.0)
  7. How the Read Optimizer works

    master

    The optimizer uses a three-stage pipeline to optimize S7 communication:

    1. Sort: Items are sorted by area, DB number, and byte offset to group adjacent reads.
    2. Merge: Sorted items in the same area/DB with a gap smaller than multi_read_max_gap are merged into contiguous read blocks.
    3. Packetize: Merged blocks are packed into PDU-sized packets, respecting the negotiated PDU length's request and reply size budgets.

    Additionally, the optimizer supports Plan caching: it caches the merge/packetize plan for repeated calls with the same item layout. This is highly effective for PLC polling loops where the same set of variables is read repeatedly.

  8. Understand S7 protocol data addressing limitations

    master

    Because python-snap7 implements the S7 protocol over TCP/IP, it is subject to the following protocol-level constraints:

    • No Symbol/Tag Name Resolution: You cannot read tag or symbol names from the PLC. Symbol names are stored in the TIA Portal project file, not the PLC. You must address data directly using the area, DB number, and byte offset.
    • No Automatic Data Structure Discovery: The PLC only stores raw bytes. It does not store the structure or layout of Data Blocks (DBs). You must manually define your data layout (e.g., using struct or similar logic) within your Python code.
    • Incomplete Backups: While you can upload individual blocks, you cannot create a full PLC project backup; full backups require TIA Portal.
  9. Write a Boolean value using the read-modify-write pattern

    master

    You cannot write a single bit directly to a PLC. To change a bit (BOOL), you must follow a read-modify-write pattern:

    1. Read the entire byte containing the bit.
    2. Use util.set_bool to modify the bit in the local bytearray.
    3. Write the entire byte back to the PLC.

    Warning: Never write a freshly created bytearray for booleans, as this will overwrite all other bits in that byte with zeros.

    from s7 import util
    
    # Read DB1.DBX0.3 (bit 3 of byte 0)
    data = client.db_read(1, 0, 1)
    value = util.get_bool(data, 0, 3)
    print(f"DB1.DBX0.3 = {value}")
    
    # Write DB1.DBX0.3 -- read first, then modify, then write
    data = client.db_read(1, 0, 1)
    util.set_bool(data, 0, 3, True)
    client.db_write(1, 0, data)
  10. Authenticate with password-protected PLCs

    master

    For PLCs that require password authentication, pass the password keyword argument to the connect() method. This is typically used in conjunction with use_tls=True for S7CommPlus V2.

    from s7commplus import Client
    
    client = Client()
    client.connect("192.168.1.10", use_tls=True, password="my_plc_password")
    data = client.db_read(1, 0, 4)
    client.disconnect()
  11. Configure PUT/GET access for S7-1200 and S7-1500

    master

    To use the legacy classic S7 protocol (via s7.Client) with S7-1200 and S7-1500 PLCs, you must enable the PUT/GET option in TIA Portal.

    Important Security Note: PUT/GET access provides unauthenticated read/write access to PLC memory. Only enable this on networks that are properly segmented and secured.

    Note on S7CommPlus: If you use s7commplus.Client, the S7CommPlus protocol does not require PUT/GET to be enabled. PUT/GET is only required when using the legacy s7.Client.