Skip to main content

pyads-agile

pyads-agile is a Python wrapper for the Beckhoff TwinCAT ADS library.

This distribution is maintained by Agile Automation Technologies GmbH and is based on the excellent upstream pyads project created by Stefan Lehmann: https://github.com/stlehmann/pyads

pyads-agile intentionally stays drop-in compatible with pyads. The public API, module name (import pyads), and supported interpreter/OS matrix mirror upstream, so existing applications can switch distributions without code changes. Current validated support target is Python 3.13 (CI runs on 3.13).

Attribution

  • Original project: pyads by Stefan Lehmann
  • Fork maintainer: Filippo Boido filippo.boido@agileautomation.eu (Agile Automation Technologies GmbH)
  • License: MIT
  • This repository keeps upstream credit and license notices as required

See ACKNOWLEDGMENTS.md for details.

Installation

Install the distribution:

pip install pyads-agile

Import stays compatible:

import pyads

Versioning

pyads-agile uses its own independent Semantic Versioning (MAJOR.MINOR.PATCH). It does not mirror upstream pyads version numbers.

Scope

This package provides Python APIs for communicating with TwinCAT devices using:

  • TcAdsDll.dll on Windows
  • adslib.so on Linux

Agile-specific enhancements

Beyond compatibility, this fork currently focuses on improved RPC ergonomics:

  • Convenient RPC object proxies. Connection.get_object() exposes TwinCAT function blocks as Python objects and lets you configure return and parameter types per method:

    TwinCAT requirement: each callable method must be annotated in PLC code with {attribute 'TcRpcEnable'} directly above the method declaration.

    rpc = plc.get_object(
        "GVL.fbTestRemoteMethodCall",
        method_return_types={"m_iSimpleCall": pyads.PLCTYPE_INT},
    )
    result = rpc.m_iSimpleCall()
    
  • Multi-parameter RPC calls with native syntax. Configure method signatures once and then call methods like normal Python methods:

    rpc = plc.get_object(
        "GVL.fbTestRemoteMethodCall",
        method_return_types={"m_iSum": pyads.PLCTYPE_INT},
        method_parameters={"m_iSum": [pyads.PLCTYPE_INT, pyads.PLCTYPE_INT]},
    )
    result = rpc.m_iSum(5, 5)
    
  • Typed RPC interfaces for IntelliSense. Decorate a Python class with @pyads.ads_path("GVL.fbTestRemoteMethodCall"), annotate method arguments and return types with TwinCAT PLC types, and pass the class into Connection.get_object. The returned proxy is typed as your class so IDEs can offer completions:

    @pyads.ads_path("GVL.fbTestRemoteMethodCall")
    class FB_TestRemoteMethodCall:
        def m_iSum(
            self,
            a: pyads.PLCTYPE_INT,
            b: pyads.PLCTYPE_INT,
        ) -> pyads.PLCTYPE_INT:
            ...
    
    rpc = plc.get_object(FB_TestRemoteMethodCall)
    result = rpc.m_iSum(5, 5)
    

    You can still use low-level direct calls when needed:

    result = plc.call_rpc_method(
        "GVL.fbTestRemoteMethodCall#m_iSimpleCall",
        return_type=pyads.PLCTYPE_INT,
        write_value=42,
        write_type=pyads.PLCTYPE_INT,
    )
    
  • Serialized async ADS runtime. AsyncConnection executes all ADS calls on a dedicated worker thread per connection (in-order, race-safe on connection state), and exposes awaitable helpers and submit-style futures:

    import asyncio
    import pyads
    
    async def main() -> None:
        async with pyads.AsyncConnection("127.0.0.1.1.1", pyads.PORT_TC3PLC1) as plc:
            fut = plc.submit_sum_read(["GVL.int_val", "GVL.bool_val"])
            # ... do other work
            values = await fut
    
            await plc.sum_write({"GVL.int_val": int(values["GVL.int_val"]) + 1})
    
    asyncio.run(main())
    
  • Runtime discovery and notification streams. Version 0.4 exposes immutable symbol/datatype metadata and a cleanup-safe async iterator for online values. route_policy="existing_only" tells pyads-agile to use the TwinCAT router's current route without creating or deleting one:

    import asyncio
    import pyads
    
    async def inspect_runtime() -> None:
        async with pyads.AsyncConnection(
            "127.0.0.1.1.1",
            pyads.PORT_TC3PLC1,
            route_policy="existing_only",
        ) as plc:
            upload = await plc.get_upload_info()
            symbols = await plc.get_all_symbol_info()
            data_types = await plc.get_all_data_types()
            print(upload, len(symbols), len(data_types))
    
            async with plc.subscribe(
                "MAIN.fbConveyor.eState",
                pyads.PLCTYPE_DINT,
                cycle_time=0.1,  # seconds; length is inferred
            ) as changes:
                sample = await anext(changes)
                print(sample.value, sample.timestamp)
    
    asyncio.run(inspect_runtime())
    

    Synchronous callers can use get_upload_info(), get_symbol_info(), get_all_symbol_info(), get_all_data_types(), and get_symbol_version() on Connection. Upload-info v3 retains the target code page, pointer width, base-type and UTF-8 flags; uploaded names and comments are decoded with that advertised code page. Call clear_symbol_cache() before a manual generation refresh (the complete symbol upload also invalidates it automatically). read_list_by_name_detailed() / write_list_by_name_detailed() and their async sum_*_detailed() counterparts retain the ADS result for every item, which lets diagnostic clients distinguish unavailable symbols from transport or datatype failures. Pass symbol_metadata={name: AdsSymbolInfo(...)} to a detailed sum read or write to dispatch against an already approved immutable layout. The complete mapping is validated before any subcommand and bypasses symbol lookup and cache state. Detailed reads additionally accept raw_data_names for values that must remain copied bytes for a metadata-driven caller codec. Zero-size and exported bit-value symbols are reported as unsupported instead of being treated as byte-aligned values. Use get_symbol_version() to bind approval to TwinCAT's symbol-table generation and recheck it immediately before dispatch.

    subscribe(..., cycle_time=..., max_delay=...) accepts seconds and infers the notification length. A caller-supplied NotificationAttrib remains available for advanced modes and cannot be combined with these timing shortcuts.

  • Async wrappers for the synchronous pyads Connection API. AsyncConnection now mirrors the core synchronous read/write surface while keeping single-threaded serialized execution under the hood. For most methods you get both:

    • submit_* returning asyncio.Future
    • async method variant that awaits the same operation

    Covered wrappers include:

    • read, write, read_write
    • read_by_name, write_by_name
    • read_structure_by_name, write_structure_by_name
    • read_state, read_device_info, write_control
    • get_local_address, get_handle, release_handle, set_timeout
    • sum_read / sum_write (submit_sum_read / submit_sum_write)
    import asyncio
    import pyads
    
    async def main() -> None:
        async with pyads.AsyncConnection("127.0.0.1.1.1", pyads.PORT_TC3PLC1) as plc:
            # Await-style
            value = await plc.read_by_name("GVL.int_val", pyads.PLCTYPE_INT)
            await plc.write_by_name("GVL.int_val", value + 1, pyads.PLCTYPE_INT)
    
            # Submit-style
            fut = plc.submit_read_state()
            state = await fut
            print(state)
    
    asyncio.run(main())
    
  • Async typed RPC objects. Use @pyads.ads_async_path(...) with AsyncConnection.get_async_object(...) for type-safe async RPC interfaces. Method calls return asyncio.Future objects:

    @pyads.ads_async_path("GVL.fbTestRemoteMethodCall")
    class FB_TestRemoteMethodCall:
        def m_iSum(
            self,
            a: pyads.PLCTYPE_INT,
            b: pyads.PLCTYPE_INT,
        ) -> asyncio.Future[pyads.PLCTYPE_INT]:
            ...
    
    async def main(plc: pyads.AsyncConnection) -> None:
        rpc = plc.get_async_object(FB_TestRemoteMethodCall)
        future = rpc.m_iSum(5, 5)
        result = await future
        print(result)
    
  • Native stepchain async RPC interfaces. Use @pyads.ads_async_path(...) on the interface, inherit from pyads.StepChainRpcInterface, and mark stepchain entry methods with @pyads.stepchain_start. Calls return a StepChainOperation containing:

    • accepted: RPC-return phase
    • done: completion phase based on PLC status fields
    • await op: completion snapshot with the latest ADS status symbol values The generic parameter on StepChainOperation[...] describes the ADS transport return type for the accepted phase.
    @pyads.ads_async_path("GVL.fbTestRemoteStepChainMethodCall")
    class FB_TestRemoteStepChainMethodCall(pyads.StepChainRpcInterface):
        __stepchain_completion__ = "poll"  # or "notify"
    
        @pyads.stepchain_start
        def m_xStartStepChain(
            self,
            udiRequestId: pyads.PLCTYPE_UDINT,
        ) -> pyads.StepChainOperation[pyads.PLCTYPE_BOOL]:
            ...
    
    async def run_stepchain(plc: pyads.AsyncConnection) -> None:
        rpc = plc.get_async_object(FB_TestRemoteStepChainMethodCall)
        status_root = rpc.status_symbol()
    
        # udiRequestId is auto-generated if omitted.
        op = rpc.m_xStartStepChain()
    
        accepted = await op.accepted
        if not accepted:
            raise RuntimeError("Stepchain start rejected by PLC.")
    
        # Wait until status reports completion or error and capture snapshot.
        completion_snapshot = await op
        request_id_symbol = f"{status_root}.udiRequestId"
        print("Completed request", completion_snapshot[request_id_symbol])
    
        # Built-in framework status read (predefined structure)
        status = await rpc.read_status()
        print(status["udiStep"], status["sStepName"])
    

    Completion backend options:

    • completion="poll": periodic sum_read checks (poll_interval/timeout_s)
    • completion="notify": ADS notifications trigger status reads in asyncio

    Built-in predefined stepchain status fields:

    • udiRequestId, xBusy, xDone, xError, diErrorCode, udiStep, sStepName

    Repository references:

Features

  • connect to remote TwinCAT devices
  • create routes on Linux and on remote PLCs
  • support for TwinCAT 2 and TwinCAT 3
  • read and write values by name or by address
  • read and write DUTs (structures)
  • notification callbacks
  • immutable upload, symbol, and datatype discovery metadata
  • cleanup-safe async notification streams
  • structured per-item sum-read and sum-write results
  • typed RPC interfaces via @pyads.ads_path(...)
  • async typed RPC interfaces via @pyads.ads_async_path(...)
  • serialized asyncio runtime via pyads.AsyncConnection
  • async wrappers for core sync ADS methods (submit_* + awaitable variants)
  • async typed RPC proxies via get_async_object(...)
  • native stepchain async RPC flow via StepChainRpcInterface + @pyads.stepchain_start
  • stepchain completion backends: polling (poll) and notification-driven (notify)

Basic usage

import pyads

plc = pyads.Connection("127.0.0.1.1.1", pyads.PORT_TC3PLC1)
plc.open()
i = plc.read_by_name("GVL.int_val")
plc.write_by_name("GVL.int_val", i)
plc.close()

Contribution Policy

This repository is maintained on a best-effort basis for internal and product needs.

At this time, we do not accept unsolicited pull requests, and we may not be able to respond to feature requests or general support issues.

Release files for pyads-agile 0.4.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyads-agile 0.4.2
File Size Uploaded
pyads_agile-0.4.2.tar.gz 324.2 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for pyads-agile 0.4.2
File
pyads_agile-0.4.2-py3-none-win_arm64.whl Python 3 none Windows ARM64 Details
pyads_agile-0.4.2-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
pyads_agile-0.4.2-py3-none-win32.whl Python 3 none Windows x86-32 Details
pyads_agile-0.4.2-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl Python 3 none Linux glibc 2.28+ x86-64, Linux glibc 2.24+ x86-64 Details
pyads_agile-0.4.2-py3-none-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl Python 3 none Linux glibc 2.28+ ARM64, Linux glibc 2.24+ ARM64 Details
pyads_agile-0.4.2-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
pyads_agile-0.4.2-py3-none-macosx_10_15_x86_64.whl Python 3 none macOS 10.15+ x86-64 Details

Total release size: 1.6 MB

Release files / pyads_agile-0.4.2.tar.gz

Download URL pyads_agile-0.4.2.tar.gz
Size 324.2 kB
Tags Source
SHA-256 checksum
How to use checksums
8cd40ea1d22d79f6eebc8e527586b0821a8aa637b08114d0cbbba674da9ce866
BLAKE2b-256 checksum
How to use checksums
21559d212d63c6b9e938b52355c0f8e4c02677e50ccd7e8316fd769daf0c788f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release files / pyads_agile-0.4.2-py3-none-win_arm64.whl

Download URL pyads_agile-0.4.2-py3-none-win_arm64.whl
Size 115.6 kB
Tags Python 3 Windows ARM64
SHA-256 checksum
How to use checksums
1d65787521835eaa5af92d915ea6aa396e661954397801a594927d6faa884b46
BLAKE2b-256 checksum
How to use checksums
fa3c572679e9f75f8a05ced838223d56c80cb1afc16397c575c5b1a3c082db0e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release files / pyads_agile-0.4.2-py3-none-win_amd64.whl

Download URL pyads_agile-0.4.2-py3-none-win_amd64.whl
Size 115.6 kB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
22ced0438d64ff31c4ab49c5fb9a7d2d2fc96680abf78c4f706e512361b70c33
BLAKE2b-256 checksum
How to use checksums
602cb5c5475ad88f989a0e3e371bd9ad8c35336c4f86fc9c9d8fc842bdcc8def
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release files / pyads_agile-0.4.2-py3-none-win32.whl

Download URL pyads_agile-0.4.2-py3-none-win32.whl
Size 115.6 kB
Tags Python 3 Windows x86-32
SHA-256 checksum
How to use checksums
2dbcda2fd8f5224bb972cf366d87669a5b33325916cae44a758fcfaffd6f0519
BLAKE2b-256 checksum
How to use checksums
ca0b7dca649409869c166ed569b2a0a650c8da8157b9b49dd62acc2d8ccc125c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release files / pyads_agile-0.4.2-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl

Download URL pyads_agile-0.4.2-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Size 280.0 kB
Tags Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64 Python 3
SHA-256 checksum
How to use checksums
c41b6896c29c0b1c65bbd2d3abe31acff6128f3425f2c99cd582eb777ccb7af3
BLAKE2b-256 checksum
How to use checksums
8a2f1cdac94e0ebbdead9e89e47a0c57b744b2296b324fd7122a9587d6f5684c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release files / pyads_agile-0.4.2-py3-none-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl

Download URL pyads_agile-0.4.2-py3-none-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
Size 258.3 kB
Tags Linux glibc 2.24+ ARM64 Linux glibc 2.28+ ARM64 Python 3
SHA-256 checksum
How to use checksums
6c900a6904ceb4d4030c63c13878efa884a7c8d64f9da06ae4f4f7dcaded23e5
BLAKE2b-256 checksum
How to use checksums
cf17e6bdcdaac00f4a54067640d56595c2808854cd3e37b07ac32b3803813200
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release files / pyads_agile-0.4.2-py3-none-macosx_11_0_arm64.whl

Download URL pyads_agile-0.4.2-py3-none-macosx_11_0_arm64.whl
Size 208.2 kB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
564eb0b2514d0086f183b8c324f53a14b93155607e6ce3ff57c96e032265373c
BLAKE2b-256 checksum
How to use checksums
8753daacb54588ed629a55bdc0f85409e8ec2db289d2554f71b92feaaa1c49de
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release files / pyads_agile-0.4.2-py3-none-macosx_10_15_x86_64.whl

Download URL pyads_agile-0.4.2-py3-none-macosx_10_15_x86_64.whl
Size 216.3 kB
Tags Python 3 macOS 10.15+ x86-64
SHA-256 checksum
How to use checksums
1a8d8f885cc4acadaf678cc6f7948e1e9cf5b4f86e6742bfb7e2330c82a38fd3
BLAKE2b-256 checksum
How to use checksums
109b7cdf8e617a4157a7c051f717bfc7eaf169383db71f2a4d77c8d8025c279c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.2 This release

8 release files

0.4.0

8 release files

0.3.4

8 release files

0.3.3

8 release files

0.3.2

8 release files

0.3.1

8 release files

0.3.0

8 release files

0.2.0

8 release files

0.1.1

3 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page