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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9ce59cfed4b05c0d06db9ff02d683aa65272f409dbe6c78e53db65ddcf5736f9
|
|
| MD5 |
1b2809dfb7887bb2d6e2d54a06a5685f
|
|
| BLAKE2b-256 |
7f34cb829526c4050c85b991fafcd25a87b6c0b0c2aed5626eb06e667177b6b1
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ffd7e8cfef9001f4510a6e92d2d9e6a9b28b4f693dbb0d0c877093454feee66e
|
|
| MD5 |
8abf013c97dc38b7d15c20ab24790021
|
|
| BLAKE2b-256 |
df7522f52d92b77e480715948d96dff909ee4347b698dca2024aaa7eb54cb5f0
|