Skip to main content

Agile-maintained Python wrapper for the TwinCAT ADS library, based on pyads

Project description

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())
    
  • Async wrappers for Stefan's synchronous 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_stepchain_path(...) to tell the async proxy that this is a long-running state-machine call. Calls return a StepChainOperation containing:

    • accepted: RPC-return phase
    • done: completion phase based on PLC status fields
    • await op: same as await op.done
    @pyads.ads_stepchain_path(
        "GVL.fbTestRemoteStepChainMethodCall",
        # Optional defaults shown explicitly:
        completion="poll",  # or "notify"
        status_field="stStepStatus",
        request_id_field="udiRequestId",
        request_id_arg="udiRequestId",
        busy_field="xBusy",
        done_field="xDone",
        error_field="xError",
        error_code_field="diErrorCode",
    )
    class FB_TestRemoteStepChainMethodCall:
        def m_xStartStepChain(
            self,
            udiRequestId: pyads.PLCTYPE_UDINT,
        ) -> pyads.PLCTYPE_BOOL:
            ...
    
    async def run_stepchain(plc: pyads.AsyncConnection) -> None:
        rpc = plc.get_async_object(FB_TestRemoteStepChainMethodCall)
    
        # 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.
        await op
    
        # 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

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
  • 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 @pyads.ads_stepchain_path(...)
  • 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.

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

pyads_agile-0.3.0.tar.gz (302.5 kB view details)

Uploaded Source

Built Distributions

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

pyads_agile-0.3.0-py3-none-win_arm64.whl (94.7 kB view details)

Uploaded Python 3Windows ARM64

pyads_agile-0.3.0-py3-none-win_amd64.whl (94.7 kB view details)

Uploaded Python 3Windows x86-64

pyads_agile-0.3.0-py3-none-win32.whl (94.7 kB view details)

Uploaded Python 3Windows x86

pyads_agile-0.3.0-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (259.2 kB view details)

Uploaded Python 3manylinux: glibc 2.24+ x86-64manylinux: glibc 2.28+ x86-64

pyads_agile-0.3.0-py3-none-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl (237.5 kB view details)

Uploaded Python 3manylinux: glibc 2.24+ ARM64manylinux: glibc 2.28+ ARM64

pyads_agile-0.3.0-py3-none-macosx_11_0_arm64.whl (189.6 kB view details)

Uploaded Python 3macOS 11.0+ ARM64

pyads_agile-0.3.0-py3-none-macosx_10_15_x86_64.whl (195.5 kB view details)

Uploaded Python 3macOS 10.15+ x86-64

File details

Details for the file pyads_agile-0.3.0.tar.gz.

File metadata

  • Download URL: pyads_agile-0.3.0.tar.gz
  • Upload date:
  • Size: 302.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyads_agile-0.3.0.tar.gz
Algorithm Hash digest
SHA256 84eadd7a7e3d08226b0000fabdce23052e2cd3c7181fecc292b20e0778e9810c
MD5 59ec41a4e9d21acab5b9c4ba33adda5d
BLAKE2b-256 78b2b7ed8af699432de3de9cd7e0fb96512f077148fded76e51689705077ddcf

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyads_agile-0.3.0.tar.gz:

Publisher: python-publish.yml on AgileAutomationTechnologies/pyads-agile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyads_agile-0.3.0-py3-none-win_arm64.whl.

File metadata

  • Download URL: pyads_agile-0.3.0-py3-none-win_arm64.whl
  • Upload date:
  • Size: 94.7 kB
  • Tags: Python 3, Windows ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyads_agile-0.3.0-py3-none-win_arm64.whl
Algorithm Hash digest
SHA256 f14b3fc38c30ec46fb291eb4d15c7deb2e5122f62701c8c6141ee493195c250a
MD5 fb478567229bd2333f43aebc29ef9fe9
BLAKE2b-256 4644b4436bd0255bb0faf3ec540fea27f996321f90a48c8f76618fe0b54daaba

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyads_agile-0.3.0-py3-none-win_arm64.whl:

Publisher: python-publish.yml on AgileAutomationTechnologies/pyads-agile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyads_agile-0.3.0-py3-none-win_amd64.whl.

File metadata

  • Download URL: pyads_agile-0.3.0-py3-none-win_amd64.whl
  • Upload date:
  • Size: 94.7 kB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyads_agile-0.3.0-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 86bc43d4a1497888f112a72815f5d6f4799b5a5184cb82401f83ecb647fee5aa
MD5 ce9a2b1a25a69a32fcd76bcb305b01b8
BLAKE2b-256 328bc7477158bec7bdb7f3a0b0375cfae1631767d31a9408ad90acb87983902a

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyads_agile-0.3.0-py3-none-win_amd64.whl:

Publisher: python-publish.yml on AgileAutomationTechnologies/pyads-agile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyads_agile-0.3.0-py3-none-win32.whl.

File metadata

  • Download URL: pyads_agile-0.3.0-py3-none-win32.whl
  • Upload date:
  • Size: 94.7 kB
  • Tags: Python 3, Windows x86
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyads_agile-0.3.0-py3-none-win32.whl
Algorithm Hash digest
SHA256 23e10f76b800b949aa3d42ab4fed0bdc4224f7b6464172586c8052c8e76c17dc
MD5 e868c7bbedbc48a82157df10ec6e97bf
BLAKE2b-256 7827562845f0e0d8c73364f75e97eb72af2781d0beaf2a74b860fa63a9cc5552

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyads_agile-0.3.0-py3-none-win32.whl:

Publisher: python-publish.yml on AgileAutomationTechnologies/pyads-agile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyads_agile-0.3.0-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for pyads_agile-0.3.0-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 2443b635fd7be4c851b83dc29a29bb53cdfc37636ac4b0e656163ac79110d9d2
MD5 b06b7df8ce1c932d8ed3f2294b6a87cb
BLAKE2b-256 dba413cdaa4cf1b9d45a3eaaf5fefd47cecd284e2c765e19ac6220be430e3a5c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyads_agile-0.3.0-py3-none-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl:

Publisher: python-publish.yml on AgileAutomationTechnologies/pyads-agile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyads_agile-0.3.0-py3-none-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for pyads_agile-0.3.0-py3-none-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 6412ca3c00911d0ed34afe35ed6133ff0e13878aefda62c7ba4f227cff014e00
MD5 268690527645105e7417351dd5772179
BLAKE2b-256 a3b63b6e7aa00da3f981793365b0f87d96cdd12eff29014f17da0d97b0a01fe3

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyads_agile-0.3.0-py3-none-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl:

Publisher: python-publish.yml on AgileAutomationTechnologies/pyads-agile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyads_agile-0.3.0-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pyads_agile-0.3.0-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 e052ec7d2802ed7409a33f138759d5c1b53b09d8532ddb54d487388ef5c6a7f4
MD5 df277dedba1fe58896d28cd1271b5feb
BLAKE2b-256 e8538e995d2859283086cdd756ef2867413aafa3d72e00d63431eff874a09adb

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyads_agile-0.3.0-py3-none-macosx_11_0_arm64.whl:

Publisher: python-publish.yml on AgileAutomationTechnologies/pyads-agile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyads_agile-0.3.0-py3-none-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for pyads_agile-0.3.0-py3-none-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 0584a54682b55e18ce60369883258896da15af5ee42ac68d01bddf362a59bfe0
MD5 56a47b70e817ecfb819cc68a08fa5728
BLAKE2b-256 933bb9ceae75ea57b5f67d9eb8ab8862031f00f509e6c01237592a996ea3112e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyads_agile-0.3.0-py3-none-macosx_10_15_x86_64.whl:

Publisher: python-publish.yml on AgileAutomationTechnologies/pyads-agile

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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