Unofficial Python implementation of Siemens S7 communication protocol
Project description
python-s7comm
Unofficial Python implementation of the Siemens S7 communication protocol for interacting with Siemens S7 PLCs
Note: I only have an S7-1200 to test with, so I can't guarantee it works with other models (S7-300, S7-400, S7-1500).
Disclaimer: This project is provided "as is", without warranty of any kind, express or implied. The author assumes no liability for any damage, loss, downtime, or safety issues resulting from the use of this software, including but not limited to damage to PLCs, industrial equipment, production systems, or data.
This library is an unofficial, experimental implementation of the S7 protocol and is not intended for production or safety-critical use. It was created primarily for educational and research purposes.
The software has not been certified, validated, or tested for industrial deployment. Use at your own risk.
Always test thoroughly in a safe, isolated environment before connecting to live equipment.
This project is not affiliated with or endorsed by Siemens AG.
Features
- Synchronous and Asynchronous clients - Choose between
ClientandAsyncClient - High-level API - Simple string-based addressing (
"DB1.0 INT 1") - Low-level API - Direct access to
S7Comm/AsyncS7Commfor advanced use cases - Read/Write operations - Single and multi-variable read/write support
- SZL (System Status List) - Read CPU state, module identification, and other diagnostic information
- PLC Control - Stop PLC execution
- Type-safe - Full type hints with mypy strict mode
Installation
pip install python-s7comm
Or with uv:
uv add python-s7comm
Quick Start
Synchronous Client
from python_s7comm import Client
# Connect to PLC
client = Client()
client.connect(address="192.168.0.1", rack=0, slot=1)
# Read data
data = client.read_area("DB1.0 INT 1") # Read 1 INT from DB1 at offset 0
print(int.from_bytes(data, "big", signed=True))
# Write data
client.write_area("DB1.0 INT 1", (42).to_bytes(2, "big", signed=True))
# Read multiple variables
results = client.read_multi_vars([
"DB1.0 INT 1",
"DB1.2 REAL 1",
"M0 BYTE 4",
])
# Get CPU state
cpu_state = client.get_cpu_state()
print(f"CPU is in {cpu_state.name} mode")
# Disconnect
client.disconnect()
Using Context Manager
from python_s7comm import Client
with Client() as client:
client.connect(address="192.168.0.1", rack=0, slot=1)
data = client.read_area("DB1.0 BYTE 10")
Asynchronous Client
import asyncio
from python_s7comm import AsyncClient
async def main():
client = AsyncClient()
await client.connect(address="192.168.0.1", rack=0, slot=1)
# Read data
data = await client.read_area("DB1.0 DINT 2")
# Write data
await client.write_area("DB1.100 BYTE 4", b"\x01\x02\x03\x04")
# Read SZL
order_code = await client.get_order_code()
print(f"PLC Order Code: {order_code}")
await client.disconnect()
asyncio.run(main())
Note:
AsyncClientuses an internal lock to send requests sequentially. The S7 protocol does not support concurrent requests on a single connection. But if you are brave enough, you can create multipleAsyncClientinstances (e.g., one for reading, another for writing) and use them within the same event loop:
import asyncio
import struct
from python_s7comm import AsyncClient
async def periodic_reader(client: AsyncClient):
"""Reads data every 1 second - runs independently."""
data = None
while True:
response = await client.read_area("DB2.0 INT 1")
new_value = int.from_bytes(response, "big", signed=True)
if new_value != data:
print(f"Data changed from {data} to {new_value}")
data = new_value
await asyncio.sleep(1)
async def writer(client: AsyncClient):
"""Performs writes - doesn't block the reader."""
for i in range(5):
await client.write_area("DB2.0 INT 1", struct.pack("!H", i))
print(f"Write: {i}")
await asyncio.sleep(3)
async def main():
reader = AsyncClient()
writer_client = AsyncClient()
await reader.connect(address="192.168.0.1", rack=0, slot=1)
await writer_client.connect(address="192.168.0.1", rack=0, slot=1)
# Reader and writer run concurrently without blocking each other
read_task = asyncio.create_task(periodic_reader(reader))
write_task = asyncio.create_task(writer(writer_client))
await write_task # Wait for writes to complete
read_task.cancel() # Stop the periodic reader
await reader.disconnect()
await writer_client.disconnect()
asyncio.run(main())
Address Format
DB area: DB<number>.<offset>[.<bit>] <type> <count>
Other areas: <area><offset>[.<bit>] <type> <count>
Examples
| Address | Description |
|---|---|
DB1.0 INT 1 |
1 INT from DB1 at byte 0 |
DB1.100 BYTE 10 |
10 BYTEs from DB1 at byte 100 |
DB5.0.0 BOOL 1 |
Bit 0 from DB5 at byte 0 |
M0 BYTE 4 |
4 BYTEs from Marker area |
I0.0 BOOL 1 |
Input bit 0.0 |
Q0 BYTE 1 |
1 BYTE from Output area |
Supported Areas
| Area | Code | Description |
|---|---|---|
DB |
0x84 | Data Blocks |
M |
0x83 | Markers (Flags) |
I |
0x81 | Inputs |
Q |
0x82 | Outputs |
C |
0x1C | Counters |
T |
0x1D | Timers |
P |
0x80 | Peripheral I/O |
Supported Data Types
BOOL, BYTE, CHAR, WORD, INT, DWORD, DINT, REAL, COUNTER, TIMER
Connection Parameters
client = Client(
tpdu_size=1024, # COTP packet size
pdu_length=480, # S7 PDU length (negotiated)
source_tsap=0x0100, # Source TSAP
dest_tsap=0x0101, # Destination TSAP
)
client.connect(
address="192.168.0.1",
rack=0, # Rack number
slot=1, # Slot number (CPU slot)
port=102, # ISO-on-TCP port (default: 102)
)
Requirements
- Python 3.12 or newer
Tested On
- Siemens S7-1200 (6ES7 214-1HG40-0XB0)
Sources
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file python_s7comm-0.1.1.tar.gz.
File metadata
- Download URL: python_s7comm-0.1.1.tar.gz
- Upload date:
- Size: 37.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4d6c8f1b437ffe510480dd9da79352be64adb7fed7d756c06eac23e580859578
|
|
| MD5 |
2dffeb5c26586faae4c39d94b879515e
|
|
| BLAKE2b-256 |
2cb6cf431d0f747e44c5726213e309e80e845ec2988d17328c0de03b689b7978
|
Provenance
The following attestation bundles were made for python_s7comm-0.1.1.tar.gz:
Publisher:
publish.yml on nikteliy/python-s7comm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
python_s7comm-0.1.1.tar.gz -
Subject digest:
4d6c8f1b437ffe510480dd9da79352be64adb7fed7d756c06eac23e580859578 - Sigstore transparency entry: 980183903
- Sigstore integration time:
-
Permalink:
nikteliy/python-s7comm@fa9eb251cfbd3e62cac490c1465c28218a1d7700 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/nikteliy
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fa9eb251cfbd3e62cac490c1465c28218a1d7700 -
Trigger Event:
push
-
Statement type:
File details
Details for the file python_s7comm-0.1.1-py3-none-any.whl.
File metadata
- Download URL: python_s7comm-0.1.1-py3-none-any.whl
- Upload date:
- Size: 43.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
11e034c19c0ddbd1513eced3bdb6e3096583aedd2ab6c8f7b74a8d91fe1d8738
|
|
| MD5 |
4174d28a99cf42ad440dca0c76758c04
|
|
| BLAKE2b-256 |
cd50d9955b8e9cea547ecdd8d36d0c8dd8dc5dad4f307168e028668a00d9acf1
|
Provenance
The following attestation bundles were made for python_s7comm-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on nikteliy/python-s7comm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
python_s7comm-0.1.1-py3-none-any.whl -
Subject digest:
11e034c19c0ddbd1513eced3bdb6e3096583aedd2ab6c8f7b74a8d91fe1d8738 - Sigstore transparency entry: 980183937
- Sigstore integration time:
-
Permalink:
nikteliy/python-s7comm@fa9eb251cfbd3e62cac490c1465c28218a1d7700 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/nikteliy
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@fa9eb251cfbd3e62cac490c1465c28218a1d7700 -
Trigger Event:
push
-
Statement type: