Skip to main content

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

  1. Firewall: Ensure port 48898 (ADS) is open
  2. AMS Routes: Verify AMS routes are configured on target system
  3. Network: Check IP connectivity between systems

Symbol Access

  1. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aioads-0.1.0.dev2.tar.gz (47.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

aioads-0.1.0.dev2-py3-none-any.whl (51.8 kB view details)

Uploaded Python 3

File details

Details for the file aioads-0.1.0.dev2.tar.gz.

File metadata

  • Download URL: aioads-0.1.0.dev2.tar.gz
  • Upload date:
  • Size: 47.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.20.1 CPython/3.8.10 Linux/5.15.167.4-microsoft-standard-WSL2

File hashes

Hashes for aioads-0.1.0.dev2.tar.gz
Algorithm Hash digest
SHA256 21a48a0dd917b63e00222c934c757bec55e3d764817f9ff0faa20b0a6d2a2f07
MD5 0f452d61834788093510a80b1bf3af06
BLAKE2b-256 459ebe89e5444ae839577b24c3a840d43a798e431fb395de9cff164b1925ae64

See more details on using hashes here.

File details

Details for the file aioads-0.1.0.dev2-py3-none-any.whl.

File metadata

  • Download URL: aioads-0.1.0.dev2-py3-none-any.whl
  • Upload date:
  • Size: 51.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.20.1 CPython/3.8.10 Linux/5.15.167.4-microsoft-standard-WSL2

File hashes

Hashes for aioads-0.1.0.dev2-py3-none-any.whl
Algorithm Hash digest
SHA256 42943b0e7852e71b14bce8d22e3d1d784a76e2f69debb7db69194dd8fefe6eaf
MD5 badf3bd63c97a8500c8e25ef0cedf40e
BLAKE2b-256 0c18c06e198108a4f777b53855edc33e0455062efdd5332418465333aeeda7f5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page