Skip to main content

Pure-Python DNP3 outstation (IEEE 1815-2012, Level 1 subset) -- aarch64-compatible

Project description

dnp3-outstation 🐍

Pure-Python DNP3 outstation (IEEE 1815-2012, Level 1 subset).

aarch64-compatible drop-in replacement for the outstation half of dnp3-python, which ships x86_64-only wheels.

Scope (and what's deliberately not in)

✅ One TCP outstation per process, asyncio-native ✅ Group 30 / variation 5 analog inputs (32-bit float with flag byte) ✅ READ requests with qualifier 0x06 (class-0 / integrity poll) and qualifier 0x00 (8-bit range) ✅ Responses encoded as one g30v5 qualifier-0x00 header per contiguous index run (rust dnp3 + opendnp3 accept this) ✅ Datalink REQUEST_LINK_STATUS → LINK_STATUS, RESET_LINK_STATES → ACK ✅ WRITE (FC=0x02) ACKed -- master can clear IIN1.RESTART ✅ IIN1.RESTART on cold start, self-clears after first response ✅ Interop verified against the rust dnp3 v1.6 master crate (same one used by ems-industrial-gateway)

❌ Master mode ❌ Secure authentication (SAv5/SAv6) ❌ File transfer, time sync, control output ❌ Event classes 1/2/3, change-driven reporting ❌ Function codes beyond READ (0x01) and WRITE (0x02)

Anything missing comes from the same place: this lib exists to publish a small, fixed set of analog values to a polling master. That's it.

Install

pip install dnp3-outstation

Python 3.11+, pure-Python — works on any platform Python runs on (Raspberry Pi 5 aarch64 included).

Usage

import asyncio
from dnp3_outstation import AsyncOutstation

async def main():
    outstation = AsyncOutstation(
        host="0.0.0.0",
        port=20000,
        master_addr=1,
        outstation_addr=1024,
    )
    outstation.set_analog(idx=0, value=1_000_000.0)
    outstation.set_analog(idx=1, value=2_000_000.0)
    outstation.set_analog(idx=10, value=250.0)

    await outstation.start()
    try:
        while True:
            # update values on whatever cadence makes sense
            outstation.set_analog(idx=10, value=read_my_sensor())
            await asyncio.sleep(2)
    finally:
        await outstation.shutdown()

asyncio.run(main())

set_analog(idx, value, flag=0x01) updates the in-memory point database. The next master poll returns whatever's there. Flag byte defaults to 0x01 (ONLINE) per the DNP3 analog-input flag definition.

Architecture

Layered to mirror IEEE 1815's stack so each layer tests independently:

   AsyncOutstation     asyncio TCP server, lifecycle
       |
   Outstation          state + orchestration (sync)
       |
   application.py      AC/FC/IIN, g30v5 encoding, READ parsing
       |
   transport.py        FIN/FIR/SEQ segment header
       |
   datalink.py         SYNC + LEN + CTRL + addresses + CRC blocks
       |
   crc.py              CRC-16/DNP per spec section 11.7

Every layer has colocated unit tests under src/dnp3_outstation/test_*.py.

License

MIT.

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

dnp3_outstation-0.1.0.tar.gz (14.8 kB view details)

Uploaded Source

Built Distribution

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

dnp3_outstation-0.1.0-py3-none-any.whl (20.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: dnp3_outstation-0.1.0.tar.gz
  • Upload date:
  • Size: 14.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for dnp3_outstation-0.1.0.tar.gz
Algorithm Hash digest
SHA256 18b5168ed8ed9bab0993a527e94b130c8357f2c3d34cc139f6b10081faf9adce
MD5 ed747a43ce7f3571c911c211efe90b26
BLAKE2b-256 49423f1aab7f770c3adea23b32346781470bbc8212ad48aa53322b43fdf9e166

See more details on using hashes here.

File details

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

File metadata

  • Download URL: dnp3_outstation-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 20.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for dnp3_outstation-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 526733361e778c58630ef160f467457e9226644f5535895a348bb4dca487d49b
MD5 af9e145aab171544bd51dc4eb1fc0c47
BLAKE2b-256 e6c464defd6b1398c9b227d278e1401f4a31fccfa78b9f21e127cfb23ee7fbdf

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