Skip to main content

pyS7


pyS7 is a lightweight, pure Python library that implements the Siemens S7 communication protocol over ISO-on-TCP (RFC1006). It provides operations for S7-200, S7-300, S7-400, S7-1200, and S7-1500 PLC families; actual compatibility depends on CPU and PLC configuration.

Production/Stable • 2x Performance • Fully Tested

⚠️ Neither this project nor its authors are affiliated with Siemens. S7-200, S7-300, S7-400, S7-1200, and S7-1500 are registered trademarks of Siemens AG.

ha-s7plc banner

Features

  • Pure Python – No external dependencies, easy installation across platforms
  • Intuitive API – Clean, readable code with full typing support for IDE assistance
  • Async Support – Full asyncio client (AsyncS7Client) for non-blocking I/O
  • High Performance – Optimized hot paths, 2x faster request preparation (v2.5.0)
  • Graceful error handling – read_detailed() and write_detailed() provide per-tag success/failure info
  • Strict batch writes – Batch execution with structured failures and optional best-effort rollback
  • Optimized multi-variable reads – Automatically groups contiguous tags to reduce network requests
  • Automatic chunking – Transparently splits large STRING/WSTRING reads exceeding PDU size
  • CPU diagnostics – Read PLC status (RUN/STOP) and information (model, firmware) via SZL protocol
  • Broad compatibility – Supports S7-200/300/400/1200/1500 series
  • Validated protocol core – Extensive automated tests and strict type checking

Safety Notice

Industrial safety must always remain your top priority. By using pyS7 you accept full responsibility for any damage, data loss, downtime, or unintended effects. Understand your system and the implications of each operation before interacting with live equipment.

Installation

Requires Python 3.11 or later.

Upgrading from 2.x? Read the 3.0 migration guide and the evidence-based compatibility matrix.

pip install pys7

Or install from GitHub:

pip install git+https://github.com/xtimmy86x/pyS7

Quick Start

Reading data

from pyS7 import BatchWriteError, S7Client

with S7Client(address="192.168.5.100", rack=0, slot=1) as client:
    tags = [
        "DB1,X0.0",     # Bit 0 of DB1
        "DB1,SINT20",   # SINT (signed byte -128 to 127) at byte 20 of DB1
        "DB1,USINT21",  # USINT (unsigned byte 0-255) at byte 21 of DB1
        "DB1,I30",      # INT at byte 30 of DB1
        "M54.4",        # Bit 4 of marker memory
        "IW22",         # WORD at byte 22 of input area
        "QR24",         # REAL at byte 24 of output area
        "DB1,S10.5"     # String of 5 characters at byte 10 of DB1
    ]

    data = client.read(tags)
    print(data)  # [True, -50, 200, 123, True, 10, 3.14, 'Hello']

Writing data

from pyS7 import S7Client

with S7Client(address="192.168.5.100", rack=0, slot=1) as client:
    tags = ["DB1,X0.0", "DB1,SINT20", "DB1,USINT21", "DB1,I30", "DB1,R40", "DB1,S10.5"]
    values = [True, -50, 200, 25000, 1.2345, "Hello"]

    client.write(tags, values)

Graceful error handling

from pyS7 import S7Client

with S7Client(address="192.168.5.100", rack=0, slot=1) as client:
    # read_detailed() continues on errors, returns per-tag results
    results = client.read_detailed(["DB1,I0", "DB99,I0", "DB1,R4"])

    for result in results:
        if result.success:
            print(f"{result.tag}: {result.value}")
        else:
            print(f"{result.tag} failed: {result.error}")

    # write_detailed() provides per-tag success/failure info
    tags = ["DB1,I0", "DB1,I2", "DB99,I0"]
    values = [100, 200, 300]
    write_results = client.write_detailed(tags, values)

    for result in write_results:
        if result.success:
            print(f"✓ {result.tag}: Written")
        else:
            print(f"✗ {result.tag}: {result.error}")

Strict batch writes with best-effort rollback

Batch writes are not atomic. A successful result means the PLC write response reported success; pyS7 does not perform post-write read-back verification. If any result fails, commit raises BatchWriteError. Optional rollback only attempts to restore a pre-write snapshot and can fail. PLC logic, concurrent clients, or a lost connection may observe or alter partially written values before restoration.

from pyS7 import BatchWriteError, S7Client

with S7Client(address="192.168.5.100", rack=0, slot=1) as client:
    # Batch write with best-effort rollback after a reported write failure
    with client.batch_write() as batch:
        batch.add("DB1,I0", 100)
        batch.add("DB1,I2", 200)
        batch.add("DB1,R4", 3.14)
        # Auto-commits on exit, rolls back on error

    # Or with explicit control
    batch = client.batch_write(auto_commit=False)
    batch.add("DB1,I0", 100)
    batch.add("DB1,I2", 200)

    try:
        results = batch.commit()  # Returns only when every write succeeded
    except BatchWriteError as exc:
        print(f"Write failed: {exc}")
        print(exc.rollback_attempted, exc.rollback_succeeded)

Reading CPU status

from pyS7 import S7Client

with S7Client(address="192.168.5.100", rack=0, slot=1) as client:
    # Get CPU status
    status = client.get_cpu_status()
    print(f"CPU Status: {status}")  # "RUN" or "STOP"

    # Get CPU information
    info = client.get_cpu_info()
    print(f"Model: {info['module_type_name']}")
    print(f"Firmware: {info['firmware_version']}")
    print(f"Hardware: {info['hardware_version']}")

See docs/CPU_STATUS_READING.md for details.

Async client

For asyncio-based applications (SCADA dashboards, IoT, Home Assistant, FastAPI):

import asyncio
from pyS7 import AsyncS7Client

async def main():
    async with AsyncS7Client(address="192.168.5.100", rack=0, slot=1) as client:
        # Read
        values = await client.read(["DB1,I0", "DB1,R4"])
        print(values)

        # Write
        await client.write(["DB1,I0"], [42])

        # Detailed read with per-tag error handling
        results = await client.read_detailed(["DB1,I0", "DB99,I0"])
        for r in results:
            print(f"{r.tag}: {r.value if r.success else r.error}")

        # Async batch write with rollback
        async with client.batch_write() as batch:
            batch.add("DB1,I0", 100)
            batch.add("DB1,I2", 200)

        # CPU diagnostics
        status = await client.get_cpu_status()
        print(f"CPU: {status}")

asyncio.run(main())

See docs/ADVANCED_USAGE.md for concurrent patterns and advanced usage.

String data types

pyS7 supports both ASCII and Unicode strings:

# STRING (ASCII) - All S7 models
tags = ["DB1,S10.20"]  # STRING at byte 10, max 20 chars
data = client.read(tags)
print(data[0])  # "Hello World"

# WSTRING (UTF-16-BE; PLC support/configuration dependent)
tags = ["DB1,WS100.30"]  # WSTRING at byte 100, max 30 chars
data = client.read(tags)
print(data[0])  # "Hello 世界! 🌍"

# Large strings automatically chunked if exceeding PDU size
tags = ["DB1,S100.254"]  # STRING[254] - handled transparently
data = client.read(tags)  # Complete string returned

Monitoring and Metrics

Built-in metrics collection for monitoring PLC communication performance and diagnostics:

from pyS7 import S7Client

# Metrics enabled by default
client = S7Client(address="192.168.5.100", rack=0, slot=1)
client.connect()

# Perform operations
client.read(["DB1,I0", "DB1,R4"])
client.write(["DB1,I0"], [100])

# Access real-time metrics
print(f"Connected: {client.metrics.connected}")
print(f"Uptime: {client.metrics.connection_uptime:.1f}s")
print(f"Total operations: {client.metrics.total_operations}")
print(f"Success rate: {client.metrics.success_rate}%")
print(f"Error rate: {client.metrics.error_rate}%")
print(f"Avg read time: {client.metrics.avg_read_duration*1000:.1f}ms")
print(f"Throughput: {client.metrics.operations_per_minute:.1f} ops/min")

# Export to dict for logging/monitoring systems
metrics_dict = client.metrics.as_dict()

# Integration with Home Assistant, Prometheus, Grafana, etc.

See docs/METRICS.md for complete metrics documentation and integration examples.

Documentation

Guides

Technical Documentation

Quick Links

Examples

Example scripts in the examples/ directory demonstrate:

  • read_data.py – Basic reading operations
  • write_data.py – Basic writing operations
  • read_detailed_demo.py – Graceful error handling for reads
  • write_detailed_demo.py – Graceful error handling for writes
  • batch_write_demo.py – Strict batch writes with best-effort rollback
  • metrics_demo.py – Metrics collection and monitoring
  • get_cpu_status.py – CPU status monitoring
  • get_cpu_info.py – CPU information retrieval
  • read_data_tsap.py – TSAP connection example
  • bit_read_workaround.py – Bit operations
  • manage_reconnection.py – Connection handling
  • connection_state_demo.py – Connection state management
  • async_client_demo.py – Async client usage with asyncio

License

This project is distributed under the MIT License. See the LICENSE file for details.

Acknowledgements

Special thanks to filocara for the original project that inspired this work.

Metadata

Release files for pys7 3.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pys7 3.0.0
File Size Uploaded
pys7-3.0.0.tar.gz 95.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pys7 3.0.0
File Interpreter ABI Platform
pys7-3.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 156.9 kB

Release files / pys7-3.0.0.tar.gz

Download URL pys7-3.0.0.tar.gz
Size 95.9 kB
Tags Source
SHA-256 checksum
How to use checksums
8afcecfbf19d0755292e2f4fa92c4001d9cd1e08cba324e2f90dab9f18402cf8
BLAKE2b-256 checksum
How to use checksums
90d7abee8788236587605417b8aae8505d6040c30578b01bce3851afcabed04e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.15

Release files / pys7-3.0.0-py3-none-any.whl

Download URL pys7-3.0.0-py3-none-any.whl
Size 61.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5b58210a4526915e99608c59d1db816354a5235081bda0d0adf15a78d64b8154
BLAKE2b-256 checksum
How to use checksums
5f0bcef44d26f01fb13491ea4cba6e7972d76f776f38fe30a862776569cdf430
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.15

Release history Release notifications | RSS feed

3.1.1

2 release files

3.1.0

2 release files

This release

3.0.0 This release

2 release files

2.8.2

2 release files

2.8.1

2 release files

2.8.0

2 release files

2.7.0

2 release files

2.6.2

2 release files

2.6.1

2 release files

2.6.0

2 release files

2.5.0

2 release files

2.4.0

2 release files

2.3.0

2 release files

2.2.1

2 release files

2.2.0

2 release files

2.1.0

2 release files

2.0.0

2 release files

1.5.2

2 release files

1.5.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page