An asynchronous Python library for communicating with Beckhoff TwinCAT PLCs
Project description
AIOADS - Asynchronous ADS Library for Python
An asynchronous Python library for communicating with Beckhoff TwinCAT PLCs using the ADS (Automation Device Specification) protocol. This library provides high-performance, async/await-based communication with PLCs for reading symbols, data types, notifications, and more.
Features
- ✨ Fully asynchronous - Built from the ground up with asyncio
- 🚀 High performance - Efficient batch operations and smart caching
- 📡 ADS over TCP - Direct communication with TwinCAT systems
- 🔍 Symbol resolution - Automatic symbol table parsing and caching
- 📊 Data type support - Complete TwinCAT data type parsing
- 🔔 Notifications - Event-driven data change monitoring
- 🛠️ Type safety - Full typing support for better development experience
- ⚡ Smart caching - Intelligent symbol and data type caching for performance
Installation
# Ads TCP
pdm add aioads
pip install aioads
# ADS over MQTT (gmqtt)
pdm add aioads[gmqtt]
pip install aioads[gmqtt]
# Ads over MQTT (aiomqtt)
pdm add aioads[aiomqtt]
pip install aioads[aiomqtt]
Quick Start
import asyncio
from aioads import AdsClient, AmsAddress
async def main():
# Create client
client = AdsClient.create_tcp(
src=AmsAddress(net_id="192.168.1.100.1.1", port=1234),
dst=AmsAddress(net_id="192.168.1.200.1.1", port=851),
ip="192.168.1.200",
port=48898,
)
try:
# Connect to PLC
await client.connect()
# Read device state
state = await client.read_state()
print(f"PLC State: {state.ads_state.name}")
# Read single symbol
value = await client.read_symbol_by_name("MAIN.MyVariable")
print(f"Value: {value}")
# Read multiple symbols efficiently
symbols = ["MAIN.Var1", "MAIN.Var2", "MAIN.Var3"]
values = await client.read_symbols_by_names(symbols)
print(f"Values: {values}")
finally:
await client.disconnect()
if __name__ == "__main__":
asyncio.run(main())
Core Components
AdsClient
The main interface for ADS communication:
from aioads import AdsClient, AmsAddress
# Create TCP client
client = AdsClient.create_tcp(
src=AmsAddress(net_id="source.net.id.1.1", port=1234),
dst=AmsAddress(net_id="target.net.id.1.1", port=851),
ip="192.168.1.100"
)
# Connect
await client.connect()
# Read operations
state = await client.read_state()
symbols = await client.get_symbols()
data_types = await client.get_symbol_datatypes()
value = await client.read_symbol_by_name("MAIN.Variable")
values = await client.read_symbols_by_names(["Var1", "Var2"])
# Disconnect
await client.disconnect()
Batch Operations
Efficiently read multiple symbols in a single operation:
# Prepare symbol list
symbols_to_read = {
"MAIN.Temperature",
"MAIN.Pressure",
"MAIN.FlowRate",
"MAIN.Status.Running",
"MAIN.Recipe.CurrentStep"
}
# Read all symbols in one batch operation
values = await client.read_symbols_by_names(symbols_to_read)
for symbol_name, value in values.items():
print(f"{symbol_name}: {value}")
Advanced Usage
Custom Transport
You can provide your own transport implementation:
from aioads.tcp_transport import AdsTcpTransport
from aioads.ads_symbol_cache import AdsSymbolCache
transport = AdsTcpTransport(
src_address=src_address,
ip="192.168.1.100",
port=48898
)
cache = AdsSymbolCache(transport=transport, dst_address=dst_address)
client = AdsClient(transport=transport, dst_address=dst_address, cache=cache)
Performance Tuning
For high-performance applications:
# Pre-load symbol information to cache
await client.read_symbol_infos_by_names(large_symbol_list)
# Use batch reads for efficiency
start = time.perf_counter()
values = await client.read_symbols_by_names(symbols)
duration = (time.perf_counter() - start) * 1000
print(f"Read {len(values)} symbols in {duration:.2f}ms")
Concurrent Operations
Handle multiple tasks concurrently:
import asyncio
async def read_process_data(client, process_symbols):
while True:
data = await client.read_symbols_by_names(process_symbols)
# Process data...
await asyncio.sleep(0.1)
async def read_diagnostics(client, diag_symbols):
while True:
data = await client.read_symbols_by_names(diag_symbols)
# Process diagnostics...
await asyncio.sleep(1.0)
async def main():
client = AdsClient.create_tcp(...)
await client.connect()
try:
# Run multiple concurrent tasks
async with asyncio.TaskGroup() as tg:
tg.create_task(read_process_data(client, process_symbols))
tg.create_task(read_diagnostics(client, diagnostic_symbols))
finally:
await client.disconnect()
Protocol Support
ADS Commands
The library supports all major ADS commands:
- Read/Write Operations: Single and batch
- Device Information: State, version, and device info
- Symbol Management: Symbol table upload and parsing
- Data Types: Complete data type information and parsing
- Notifications: Change and cyclic notifications (Still in preview)
- Sum Commands: Efficient bulk operations
Data Types
Full support for TwinCAT data types:
- Basic Types: BOOL, BYTE, WORD, DWORD, INT, REAL, STRING, etc.
- Structured Types: STRUCT, ARRAY, UNION
- Complex Types: Custom user-defined types
- Arrays: Multi-dimensional arrays with proper indexing
Requirements
- Python 3.11+
- asyncio
- aiomqtt (optional)
Disclaimer
This project is an independent, open‑source implementation of the ADS (Automation Device Specification) protocol. It is not affiliated with, endorsed by, or supported by Beckhoff Automation GmbH & Co. KG, the developer of TwinCAT and the ADS protocol. All trademarks and product names are the property of their respective owners.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Troubleshooting
Connection Issues
- Firewall: Ensure port 48898 (ADS) is open
- AMS Routes: Verify AMS routes are configured on target system
- Network: Check IP connectivity between systems
Symbol Access
- PLC State: Ensure PLC is in RUN mode for symbol access
Contributing guidelines
AIOADS is a personal hobby project, developed and maintained in my spare time. While I aim to keep it functional and improve it over time, it may not always receive frequent updates, and features or bug fixes might take a while.
If you rely on this library in production environments, consider reviewing the code, contributing improvements, or opening issues so the community can help keep it healthy.
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 aioads-0.1.0.dev3.tar.gz.
File metadata
- Download URL: aioads-0.1.0.dev3.tar.gz
- Upload date:
- Size: 48.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: pdm/2.27.0 CPython/3.13.2 Linux/5.15.167.4-microsoft-standard-WSL2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
02ea2667a08f1083d466bf8f0a9fc632893acdf3b45e68c79ac6bdfb7c78b2f6
|
|
| MD5 |
124e2cf080c76f5fdfe3a028655fa249
|
|
| BLAKE2b-256 |
61617d08fdbeafe50fc1def8d3980018edcc99be1214db3345e634d042a50e0d
|
File details
Details for the file aioads-0.1.0.dev3-py3-none-any.whl.
File metadata
- Download URL: aioads-0.1.0.dev3-py3-none-any.whl
- Upload date:
- Size: 53.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: pdm/2.27.0 CPython/3.13.2 Linux/5.15.167.4-microsoft-standard-WSL2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1de9e1dd11c4d37ff2e7afde4bc66098d60475a719c74a19b2a5c2885467bbef
|
|
| MD5 |
ea6f3847ec4ba748568d4a1fa2e58806
|
|
| BLAKE2b-256 |
83a183972a7958b0738784d297a442c062687428ce3dcf958e1e4d95cd975676
|