Skip to main content

Write ladder logic in Python. Simulate it. Test it. Deploy it -- Currently targets AutomationDirect CLICK PLC and CircuitPython ProductivityOpen P1AM-200.

Project description

pyrung

Write ladder logic in Python. Simulate it. Test it. Deploy it.

pyrung turns Python's with block into a ladder rung — condition on the rail, instructions in the body.

from pyrung import Bool, PLCRunner, Program, Rung, out

Button = Bool("Button")
Light = Bool("Light")

with Program() as logic:
    with Rung(Button):
        out(Light)

runner = PLCRunner(logic)
with runner.active():
    Button.value = True
    runner.step()
    assert Light.value is True

Status: Core engine, Click PLC dialect, CircuitPython dialect, and VS Code debugger are implemented and tested (~26k lines, 1,600+ tests). Not yet on PyPI. API may still change.

Documentation: https://ssweber.github.io/pyrung/ LLM docs index: https://ssweber.github.io/pyrung/llms.txt LLM full context: https://ssweber.github.io/pyrung/llms-full.txt

Why?

AutomationDirect CLICK PLCs have no built-in simulator. You write logic, download it to hardware, and hope. pyrung lets you test first — same tag names, deterministic scans, real assertions. When it works, transpose it to Click.

Or don't transpose at all. Run your program as a soft PLC to test Modbus send/receive — it runs behind a Click-compatible Modbus interface, no hardware required. You can even spin up two pyrung programs and test them talking to each other. Or generate a CircuitPython scan loop for a ProductivityOpen P1AM-200 and run it on actual I/O.

Quick start

# Requires Python 3.11+
uv add pyrung

A motor with start/stop logic

from pyrung import Bool, Program, Rung, latch, reset

Start = Bool("Start")
Stop = Bool("Stop")
Running = Bool("Running")

with Program() as logic:
    with Rung(Start):
        latch(Running)
    with Rung(Stop):
        reset(Running)

Test it

from pyrung import PLCRunner

runner = PLCRunner(logic)
with runner.active():
    Start.value = True
    runner.step()
    assert Running.value is True

    # Release start — motor stays latched
    Start.value = False
    runner.step()
    assert Running.value is True

    Stop.value = True
    runner.step()
    assert Running.value is False

Map to Click hardware when you're ready

from pyrung.click import TagMap

tags = TagMap()
tags.map(Start, "X001")    # Physical input
tags.map(Stop, "X002")     # Physical input
tags.map(Running, "Y001")  # Physical output

tags.validate(logic)  # Checks against Click constraints
tags.export_nicknames("motor.csv")  # For Click programming software

What's included

Core engine — Pure f(state) → new_state scan cycle with immutable snapshots. Coils, latches, timers, counters, branching, subroutines, structured tags, edge detection, and more. Built to match real Click behavior — no surprises when you move to hardware.

Click PLC dialect — Hardware address mapping, memory bank validation, Modbus instructions, and nickname file export. Run any program as a soft PLC behind a Click-compatible Modbus interface for integration testing. Docs →

CircuitPython dialect — Generates a self-contained scan loop for P1AM-200 hardware from any pyrung program. Docs →

VS Code debugger — Step through scans, set breakpoints on rungs, force tags, diff states, and time-travel through scan history. Docs →

Learn more

Core Concepts Scan cycle, SystemState, tags, blocks
Ladder Logic Guide Full DSL reference
Tag Structures UDTs, named arrays, cloning, block config
Runner Guide Execution, time modes, history, fork
Testing Guide Unit testing with deterministic time
Forces & Debug Force values, breakpoints, time travel

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

pyrung-0.1.0.tar.gz (410.1 kB view details)

Uploaded Source

Built Distribution

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

pyrung-0.1.0-py3-none-any.whl (213.7 kB view details)

Uploaded Python 3

File details

Details for the file pyrung-0.1.0.tar.gz.

File metadata

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

File hashes

Hashes for pyrung-0.1.0.tar.gz
Algorithm Hash digest
SHA256 d06eb385aef51c5ed27c723088ec4178ec316ed722e59df69dec4903053f2899
MD5 c0766d681ad5ec67545e727f1773e5c0
BLAKE2b-256 35ae182b3a2851ac4d2311e745134d2f3918cfdd5c48c89edae7d5dc0c705e4c

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyrung-0.1.0.tar.gz:

Publisher: publish.yml on ssweber/pyrung

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

File details

Details for the file pyrung-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pyrung-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 213.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyrung-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 af8f7598e5d2a79b2bc04b93616bc420c2822e55f3f4575d115b94006650bdf8
MD5 c0b1d63cdd58a4bd6410ebb393818099
BLAKE2b-256 3fb10c5b43800017d4236120a8b3bcf39fca573295155e9bd3db299513b30e46

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyrung-0.1.0-py3-none-any.whl:

Publisher: publish.yml on ssweber/pyrung

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