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

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.0
File Size Uploaded
pyads_agile-0.4.0.tar.gz 324.3 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for pyads-agile 0.4.0
File
pyads_agile-0.4.0-py3-none-win_arm64.whl Python 3 none Windows ARM64 Details
pyads_agile-0.4.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
pyads_agile-0.4.0-py3-none-win32.whl Python 3 none Windows x86-32 Details
pyads_agile-0.4.0-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl Python 3 none Linux glibc 2.24+ x86-64, Linux glibc 2.28+ x86-64 Details
pyads_agile-0.4.0-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.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
pyads_agile-0.4.0-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.0.tar.gz

Download URL pyads_agile-0.4.0.tar.gz
Size 324.3 kB
Tags Source
SHA-256 checksum
How to use checksums
1ad17a1ad5e1a0366c3c9d2ccf8afffe3f5437837942b74760b169e9eb4c94da
BLAKE2b-256 checksum
How to use checksums
d04d89d1c2e49ccb805e62a8a15f10f742275829baf2481aed3218f840cc53c5
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.0-py3-none-win_arm64.whl

Download URL pyads_agile-0.4.0-py3-none-win_arm64.whl
Size 115.6 kB
Tags Python 3 Windows ARM64
SHA-256 checksum
How to use checksums
051677c79bfbc4e72f78c6d48488ad0583d8046381aeac28bf60be216655fdf7
BLAKE2b-256 checksum
How to use checksums
813ddc7907d2a3cbbe964ca23f195763e45906df13d19c44b71371502acac3d8
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.0-py3-none-win_amd64.whl

Download URL pyads_agile-0.4.0-py3-none-win_amd64.whl
Size 115.6 kB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
38b122903bf32a7d7dee9c93ca258690d8ce9c7eabc204e4b4b012a98d8cc2fc
BLAKE2b-256 checksum
How to use checksums
708a923eaa664201921005310ce0fcdded21c29880ef38a460bca2c11c2a60ce
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.0-py3-none-win32.whl

Download URL pyads_agile-0.4.0-py3-none-win32.whl
Size 115.6 kB
Tags Python 3 Windows x86-32
SHA-256 checksum
How to use checksums
75b4742c8307d7046bab22adb64fba983276553f89922a090bd32e2d120b1e8c
BLAKE2b-256 checksum
How to use checksums
08528282a27fcd73e781eb50cabac6d43d5f76147506d30db6091bebea3e4907
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.0-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl

Download URL pyads_agile-0.4.0-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
37d65af962cf6bdf1e657edae5ca48e156156fdc2ebb57ecaab63d54ed12a9e8
BLAKE2b-256 checksum
How to use checksums
b4c10dda3fd214f45b93ed79710577469298d3363b22f4fcf31ec7f1d00a624d
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.0-py3-none-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl

Download URL pyads_agile-0.4.0-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
03aa3d75e92de0a8b6cfa18ed2feb1dc84d4d4f878af681fcf49ad9233434a0a
BLAKE2b-256 checksum
How to use checksums
5e18d2b178e82dd72fafed2abaf2fc98c66c35b0bd0bb8b0da59248c35669aac
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.0-py3-none-macosx_11_0_arm64.whl

Download URL pyads_agile-0.4.0-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
de533765c95bfc190aa631641a8ef113b51a04610c502c7d40c502a778db7470
BLAKE2b-256 checksum
How to use checksums
28783050e96d9a85c7acdd845af352b87c69612af652ae9f71da57416d73415c
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.0-py3-none-macosx_10_15_x86_64.whl

Download URL pyads_agile-0.4.0-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
95f1bffd274602bae76b5e7ff6ab3070abbc17c1e28636723997baa5587b943d
BLAKE2b-256 checksum
How to use checksums
6afa0c9d6fd40e8b76e6701f07e9d9e7965e6efdb6148ad87b1742fbb169fc7a
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

0.4.2

8 release files

This release

0.4.0 This release

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