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.2.0.tar.gz (17.6 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.2.0-py3-none-any.whl (24.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: dnp3_outstation-0.2.0.tar.gz
  • Upload date:
  • Size: 17.6 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.2.0.tar.gz
Algorithm Hash digest
SHA256 9ce59cfed4b05c0d06db9ff02d683aa65272f409dbe6c78e53db65ddcf5736f9
MD5 1b2809dfb7887bb2d6e2d54a06a5685f
BLAKE2b-256 7f34cb829526c4050c85b991fafcd25a87b6c0b0c2aed5626eb06e667177b6b1

See more details on using hashes here.

File details

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

File metadata

  • Download URL: dnp3_outstation-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 24.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.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ffd7e8cfef9001f4510a6e92d2d9e6a9b28b4f693dbb0d0c877093454feee66e
MD5 8abf013c97dc38b7d15c20ab24790021
BLAKE2b-256 df7522f52d92b77e480715948d96dff909ee4347b698dca2024aaa7eb54cb5f0

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