Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ jobs:
uses: codecov/codecov-action@v5
with:
files: coverage.xml
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
17 changes: 0 additions & 17 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,3 @@ Install using pip::
$ pip install python-snap7

No native libraries or platform-specific dependencies are required — python-snap7 is a pure Python package that works on all platforms.


Async support
=============

An ``AsyncClient`` is available for use with ``asyncio``::

import asyncio
import snap7

async def main():
async with snap7.AsyncClient() as client:
await client.connect("192.168.1.10", 0, 1)
data = await client.db_read(1, 0, 4)
print(data)

asyncio.run(main())
6 changes: 6 additions & 0 deletions doc/API/async_client.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
AsyncClient
===========

.. warning::

The ``AsyncClient`` is **experimental**. The API may change in future
releases. If you encounter problems, please `open an issue
<https://github.com/gijzelaerr/python-snap7/issues>`_.

The :class:`~snap7.async_client.AsyncClient` provides a native ``asyncio``
interface for communicating with Siemens S7 PLCs. It has feature parity with
the synchronous :class:`~snap7.client.Client` and is safe for concurrent use
Expand Down
70 changes: 70 additions & 0 deletions doc/API/s7commplus.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
S7CommPlus (S7-1200/1500)
=========================

.. warning::

S7CommPlus support is **experimental**. The API may change in future
releases. If you encounter problems, please `open an issue
<https://github.com/gijzelaerr/python-snap7/issues>`_.

The :mod:`snap7.s7commplus` package provides support for Siemens S7-1200 and
S7-1500 PLCs, which use the S7CommPlus protocol instead of the classic S7
protocol used by S7-300/400.

Both synchronous and asynchronous clients are available. When a PLC does not
support S7CommPlus data operations, the clients automatically fall back to the
legacy S7 protocol transparently.

Synchronous client
------------------

.. code-block:: python

from snap7.s7commplus.client import S7CommPlusClient

client = S7CommPlusClient()
client.connect("192.168.1.10")
data = client.db_read(1, 0, 4)
client.disconnect()

Asynchronous client
-------------------

.. code-block:: python

import asyncio
from snap7.s7commplus.async_client import S7CommPlusAsyncClient

async def main():
client = S7CommPlusAsyncClient()
await client.connect("192.168.1.10")
data = await client.db_read(1, 0, 4)
await client.disconnect()

asyncio.run(main())

Legacy fallback
---------------

If the PLC returns an error for S7CommPlus data operations (common with some
firmware versions), the client automatically falls back to the classic S7
protocol. You can check whether fallback is active:

.. code-block:: python

client.connect("192.168.1.10")
if client.using_legacy_fallback:
print("Using legacy S7 protocol")

API reference
-------------

.. automodule:: snap7.s7commplus.client
:members:

.. automodule:: snap7.s7commplus.async_client
:members:

.. automodule:: snap7.s7commplus.connection
:members:
:exclude-members: S7CommPlusConnection
100 changes: 100 additions & 0 deletions doc/connecting.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
Connecting to PLCs
==================

This page shows how to connect to different Siemens PLC models using
python-snap7.

.. contents:: On this page
:local:
:depth: 2


Rack/Slot Reference
-------------------

.. list-table::
:header-rows: 1
:widths: 20 10 10 60

* - PLC Model
- Rack
- Slot
- Notes
* - S7-300
- 0
- 2
-
* - S7-400
- 0
- 3
- May vary with multi-rack configurations
* - S7-1200
- 0
- 1
- PUT/GET access must be enabled in TIA Portal
* - S7-1500
- 0
- 1
- PUT/GET access must be enabled in TIA Portal
* - S7-200 / Logo
- --
- --
- Use ``set_connection_params`` with TSAP addressing

.. warning::

S7-1200 and S7-1500 PLCs ship with PUT/GET communication disabled by
default. Enable it in TIA Portal under the CPU properties before
connecting. See :doc:`tia-portal-config` for step-by-step instructions.


S7-300
------

.. code-block:: python

import snap7

client = snap7.Client()
client.connect("192.168.1.10", 0, 2)

S7-400
------

.. code-block:: python

import snap7

client = snap7.Client()
client.connect("192.168.1.10", 0, 3)

S7-1200 / S7-1500
------------------

.. code-block:: python

import snap7

client = snap7.Client()
client.connect("192.168.1.10", 0, 1)

S7-200 / Logo (TSAP Connection)
--------------------------------

.. code-block:: python

import snap7

client = snap7.Client()
client.set_connection_params("192.168.1.10", 0x1000, 0x2000)
client.connect("192.168.1.10", 0, 0)

Using a Non-Standard Port
--------------------------

.. code-block:: python

import snap7

client = snap7.Client()
client.connect("192.168.1.10", 0, 1, tcp_port=1102)
106 changes: 106 additions & 0 deletions doc/connection-issues.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
Connection Issues
=================

.. contents:: On this page
:local:
:depth: 2


.. _connection-recovery:

Connection Recovery
-------------------

Network connections to PLCs can drop due to cable issues, PLC restarts, or
network problems. Use a reconnection pattern to handle this gracefully:

.. code-block:: python

import snap7
import time
import logging

logger = logging.getLogger(__name__)

client = snap7.Client()

def connect(address: str = "192.168.1.10", rack: int = 0, slot: int = 1) -> None:
client.connect(address, rack, slot)

def safe_read(db: int, start: int, size: int) -> bytearray:
"""Read from DB with automatic reconnection on failure."""
try:
return client.db_read(db, start, size)
except Exception:
logger.warning("Read failed, attempting reconnection...")
try:
client.disconnect()
except Exception:
pass
time.sleep(1)
connect()
return client.db_read(db, start, size)

def safe_write(db: int, start: int, data: bytearray) -> None:
"""Write to DB with automatic reconnection on failure."""
try:
client.db_write(db, start, data)
except Exception:
logger.warning("Write failed, attempting reconnection...")
try:
client.disconnect()
except Exception:
pass
time.sleep(1)
connect()
client.db_write(db, start, data)

For long-running applications, wrap your main loop with reconnection logic:

.. code-block:: python

while True:
try:
data = safe_read(1, 0, 10)
# process data...
time.sleep(0.5)
except Exception:
logger.error("Failed after reconnection attempt, retrying in 5s...")
time.sleep(5)


Connection Timeout
------------------

The default connection timeout is 5 seconds. You can configure it by accessing
the underlying connection object:

.. code-block:: python

import snap7

client = snap7.Client()

# Connect with a custom timeout (in seconds)
client.connect("192.168.1.10", 0, 1)

# The timeout is set on the underlying connection
# Default is 5.0 seconds
client.connection.timeout = 10.0 # Set to 10 seconds

To set the timeout **before** connecting, use ``set_connection_params`` and then
connect manually, or simply reconnect after adjusting:

.. code-block:: python

client = snap7.Client()
client.connect("192.168.1.10", 0, 1)

# Adjust timeout for slow networks
client.connection.timeout = 15.0

.. note::

If you are experiencing frequent timeouts, check your network quality first.
Typical S7 communication on a local network should respond within
milliseconds.
50 changes: 50 additions & 0 deletions doc/error-reference.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Error Message Reference
=======================

The following table maps common S7 error strings to their likely cause and fix.

.. list-table::
:header-rows: 1
:widths: 35 30 35

* - Error message
- Likely cause
- Fix
* - ``CLI : function refused by CPU (Unknown error)``
- PUT/GET communication is not enabled on the PLC, or the data block
still has optimized block access enabled.
- Enable PUT/GET in TIA Portal and disable optimized block access on each
DB. See :doc:`tia-portal-config`.
* - ``CPU : Function not available``
- The requested function is not supported on this PLC model. S7-1200 and
S7-1500 PLCs restrict certain operations.
- Check Siemens documentation for your PLC model. Some functions are only
available on S7-300/400.
* - ``CPU : Item not available``
- Wrong DB number, the DB does not exist, or the address is out of range.
- Verify the DB number exists on the PLC and that the offset and size are
within bounds.
* - ``CPU : Address out of range``
- Reading or writing past the end of a DB or memory area.
- Check the DB size in TIA Portal and ensure ``start + size`` does not
exceed it.
* - ``CPU : Function not authorized for current protection level``
- The PLC has password protection enabled.
- Remove or lower the protection level in TIA Portal under
Protection & Security.
* - ``ISO : An error occurred during recv TCP : Connection timed out``
- Network issue: PLC is unreachable, a firewall is blocking port 102, or
the PLC is not responding.
- Check network connectivity (``ping``), verify firewall rules, and ensure
the PLC is powered on and reachable.
* - ``ISO : An error occurred during send TCP : Connection timed out``
- Same as above.
- Same as above.
* - ``TCP : Unreachable peer``
- The PLC is not reachable on the network.
- Verify IP address, subnet, and routing. Ensure the PLC Ethernet port is
connected and configured.
* - ``TCP : Connection reset`` / Socket error 32 (broken pipe)
- The connection to the PLC was lost unexpectedly.
- The PLC may have been restarted, the cable disconnected, or another
client took over the connection. See :doc:`connection-issues`.
Loading
Loading