Skip to content
Open
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
11 changes: 10 additions & 1 deletion doc/API/client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ s7commplus.Client
s7commplus.AsyncClient
----------------------

The asynchronous client currently supports the TLS connection and
legitimation path. Legacy V1 SessionKey authentication is available only on
the synchronous client.

.. code-block:: python

import asyncio
Expand Down Expand Up @@ -64,7 +68,8 @@ For PLCs with custom certificates, provide the certificate paths:
Password authentication
-----------------------

Password-protected PLCs require the ``password`` keyword argument:
The synchronous client accepts the ``password`` keyword for both TLS
legitimation and the post-SessionKey exchange used by older V1 PLCs:

.. code-block:: python

Expand All @@ -75,6 +80,10 @@ Password-protected PLCs require the ``password`` keyword argument:
data = client.db_read(1, 0, 4)
client.disconnect()

For a V1 PLC, omit ``use_tls=True``. The asynchronous client has no
``password`` argument on ``connect``; on a TLS connection, authenticate
explicitly with ``await client.authenticate(password)``.

Concurrent async reads
----------------------

Expand Down
29 changes: 15 additions & 14 deletions doc/API/tags.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,28 +104,29 @@ TIA Portal V13+) do not use fixed byte offsets. The PLC internally
relocates variables between downloads, so addresses like ``DB1.DBX0.0``
are unreliable.

For optimized blocks, use :meth:`~snap7.tags.Tag.from_access_string`
with LIDs discovered via :meth:`~s7commplus.client.S7CommPlusClient.browse`:
For optimized blocks, use the low-level ``read_symbolic`` and
``write_symbolic`` methods with access paths discovered via
:meth:`~s7commplus.client.S7CommPlusClient.browse`. A typed, name-based
S7CommPlus tag API is not implemented yet; :class:`~snap7.tags.Tag` and the
``read_tag`` methods above belong to the classic ``s7.Client`` API.

.. code-block:: python

import struct

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)
variables = client.browse()
speed_info = next(item for item in variables if item["name"] == "Motor.Speed")
path = [int(part, 16) for part in speed_info["access_sequence"].split(".")]

# Symbolic values are currently exposed as raw wire bytes.
raw = client.read_symbolic(path[0], path[1:])
speed = struct.unpack(">f", raw)[0]
client.write_symbolic(path[0], path[1:], struct.pack(">f", 1500.0))

API reference
-------------
Expand Down
32 changes: 20 additions & 12 deletions doc/connecting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,13 @@ with the ``s7commplus`` extra:
.. note::

Older S7-1200 firmware (FW < 4.5) negotiates V1 of the S7CommPlus
protocol, which predates TLS and uses a different proprietary
handshake. ``Client(...)`` falls back transparently to legacy
PUT/GET on those PLCs (``db_read`` / ``db_write`` work);
``browse()`` and other CommPlus-only operations are not yet
supported on those firmwares — see issue #710.
protocol, which predates TLS and uses a SessionKey handshake instead.
The synchronous ``Client`` performs this handshake when ``use_tls`` is
false; it does not fall back to the classic PUT/GET protocol. V1 support
is experimental and the asynchronous client currently supports only the
TLS path. See `issue #710
<https://github.com/gijzelaerr/python-snap7/issues/710>`_ for the original
V1 hardware report.

TLS handshake rejected by the PLC (connection reset)
------------------------------------------------------
Expand Down Expand Up @@ -207,7 +209,9 @@ PLC Password Authentication
----------------------------

If the PLC has a password configured (``Full access (no protection)``
disabled in TIA Portal), call ``authenticate`` after ``connect``:
disabled in TIA Portal), pass it to the synchronous client's ``connect``
method. The client applies it to either the legacy SessionKey flow or the
TLS legitimation flow, as appropriate for the PLC:

.. code-block:: python

Expand All @@ -217,15 +221,19 @@ disabled in TIA Portal), call ``authenticate`` after ``connect``:
client.connect(
"192.168.1.10",
use_tls=True,
password="hunter2",
)
client.authenticate(password="hunter2")
data = client.db_read(1, 0, 4)

Authentication requires TLS to be active (``use_tls=True``). The
client auto-detects whether the PLC firmware uses the legacy SHA-1
challenge or the newer AES-256-CBC challenge. For accounts with a
username (TIA Portal V17+ user-based access control), pass it
explicitly:
For an older V1 PLC, omit ``use_tls=True``; the password is then used by the
post-SessionKey legitimation exchange. The asynchronous client currently
supports password authentication only on TLS connections, using
``await client.authenticate(...)`` after connecting.

The explicit synchronous ``authenticate`` method is also TLS-only. It
auto-detects whether the TLS PLC uses the legacy SHA-1 challenge or the newer
AES-256-CBC challenge. For accounts with a username (TIA Portal V17+
user-based access control), pass it explicitly:

.. code-block:: python

Expand Down
15 changes: 9 additions & 6 deletions doc/limitations.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
Protocol Limitations and FAQ
============================

python-snap7 implements the S7 protocol over TCP/IP. The following operations
are **not possible** with this protocol:
python-snap7 implements both the classic S7 protocol and S7CommPlus over
TCP/IP. The following limitations apply to the classic protocol exposed by
``s7.Client``; the native S7CommPlus client has different capabilities:

.. list-table::
:header-rows: 1
Expand All @@ -11,11 +12,13 @@ are **not possible** with this protocol:
* - Limitation
- Explanation
* - Read tag/symbol names from PLC
- Symbol names exist only in the TIA Portal project file, not in the PLC.
The S7 protocol only addresses data by area, DB number, and byte offset.
- The classic S7 protocol only addresses data by area, DB number, and byte
offset. The experimental ``s7commplus.Client.browse()`` API can read the
symbol tree from supported S7-1200/1500 PLCs.
* - Get DB structure or layout from PLC
- The PLC stores only raw bytes. The structure definition lives in the TIA
Portal project. You must define your data layout in your Python code.
- Classic S7 reads DBs as raw bytes, so callers must supply the layout.
S7CommPlus browsing can reconstruct type information and optimized
symbolic access paths on supported S7-1200/1500 PLCs.
* - Discover PLCs on the network
- The classic S7 protocol has no broadcast discovery mechanism. However,
python-snap7 provides PROFINET DCP discovery via the ``s7 discover``
Expand Down
Loading