pydnp3-stepfunc 1.6.0.3__cp310-cp310-manylinux1_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dnp3/__init__.py +138 -0
- dnp3/_build_ffi.py +166 -0
- dnp3/_ffi.py +64 -0
- dnp3/channel.py +240 -0
- dnp3/handler.py +509 -0
- dnp3/logging.py +93 -0
- dnp3/master.py +539 -0
- dnp3/outstation.py +400 -0
- dnp3/runtime.py +57 -0
- dnp3/types.py +517 -0
- dnp3/vendor/dnp3.h +8253 -0
- dnp3/vendor/libdnp3_ffi.so +0 -0
- pydnp3_stepfunc-1.6.0.3.dist-info/METADATA +238 -0
- pydnp3_stepfunc-1.6.0.3.dist-info/RECORD +17 -0
- pydnp3_stepfunc-1.6.0.3.dist-info/WHEEL +5 -0
- pydnp3_stepfunc-1.6.0.3.dist-info/licenses/LICENSE +21 -0
- pydnp3_stepfunc-1.6.0.3.dist-info/top_level.txt +1 -0
|
Binary file
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pydnp3-stepfunc
|
|
3
|
+
Version: 1.6.0.3
|
|
4
|
+
Summary: Python bindings for the stepfunc/dnp3 Rust library via cffi
|
|
5
|
+
Author: f0rw4rd
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/f0rw4rd/dnp3-python
|
|
8
|
+
Project-URL: Repository, https://github.com/f0rw4rd/dnp3-python
|
|
9
|
+
Project-URL: Issues, https://github.com/f0rw4rd/dnp3-python/issues
|
|
10
|
+
Keywords: dnp3,scada,ics,industrial-control-systems,modbus,protocol,master,outstation,rtu,power-systems
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Classifier: Topic :: System :: Networking
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: cffi>=1.15.0
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-timeout>=2.0; extra == "dev"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# dnp3-python
|
|
35
|
+
|
|
36
|
+
Python bindings for the [stepfunc/dnp3](https://github.com/stepfunc/dnp3) Rust library via cffi.
|
|
37
|
+
|
|
38
|
+
[](https://github.com/f0rw4rd/dnp3-python/actions/workflows/tests.yml)
|
|
39
|
+
|
|
40
|
+
This library provides a Pythonic API for DNP3 (Distributed Network Protocol 3) master
|
|
41
|
+
and outstation operations, built on the production-quality stepfunc/dnp3 implementation.
|
|
42
|
+
It supports TCP, TLS, serial, and UDP transports with full Secure Authentication support.
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
- **Master station** - Integrity polls, class-based reads, specific group/variation reads
|
|
47
|
+
- **Control operations** - Select-Before-Operate (SBO), Direct Operate, analog outputs
|
|
48
|
+
- **Device attributes** - Read Group 0 device attribute strings
|
|
49
|
+
- **Outstation server** - Create test outstations with configurable databases
|
|
50
|
+
- **Time synchronization** - LAN and non-LAN time sync modes
|
|
51
|
+
- **Restart commands** - Cold and warm restart with delay reporting
|
|
52
|
+
- **Multiple transports** - TCP, TLS, serial, UDP channel creation
|
|
53
|
+
- **Logging** - Configurable log levels, text/JSON output, custom callbacks
|
|
54
|
+
- **Thread-safe** - All handlers use locking for concurrent access
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
### Prerequisites
|
|
59
|
+
|
|
60
|
+
You need the compiled stepfunc/dnp3 C FFI library (`libdnp3_ffi.so` and `dnp3.h`).
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Clone and build the Rust library
|
|
64
|
+
git clone https://github.com/stepfunc/dnp3.git stepfunc-dnp3
|
|
65
|
+
cd stepfunc-dnp3
|
|
66
|
+
cargo build --release -p dnp3-ffi
|
|
67
|
+
|
|
68
|
+
# Generate C bindings
|
|
69
|
+
cargo build --release -p dnp3-bindings
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Install dnp3-python
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Install from local checkout
|
|
76
|
+
pip install -e .
|
|
77
|
+
|
|
78
|
+
# Or with dev dependencies
|
|
79
|
+
pip install -e ".[dev]"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The library locates `dnp3.h` and `libdnp3_ffi.so` automatically from a sibling
|
|
83
|
+
`stepfunc-dnp3/` directory. You can also set environment variables:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
export DNP3_HEADER_PATH=/path/to/dnp3.h
|
|
87
|
+
export DNP3_LIB_PATH=/path/to/libdnp3_ffi.so
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Quick Start
|
|
91
|
+
|
|
92
|
+
### Master - Read Data from Outstation
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from dnp3 import Runtime, MasterChannelConfig, ReadHandler
|
|
96
|
+
from dnp3.channel import create_tcp_channel
|
|
97
|
+
from dnp3.logging import configure_logging, LogLevel
|
|
98
|
+
|
|
99
|
+
configure_logging(LogLevel.INFO)
|
|
100
|
+
|
|
101
|
+
with Runtime() as runtime:
|
|
102
|
+
handler = ReadHandler()
|
|
103
|
+
channel = create_tcp_channel(
|
|
104
|
+
runtime,
|
|
105
|
+
endpoints=["127.0.0.1:20000"],
|
|
106
|
+
config=MasterChannelConfig(address=1),
|
|
107
|
+
)
|
|
108
|
+
assoc = channel.add_association(address=1024, read_handler=handler)
|
|
109
|
+
channel.enable()
|
|
110
|
+
|
|
111
|
+
# Integrity poll (all classes)
|
|
112
|
+
channel.read(assoc)
|
|
113
|
+
|
|
114
|
+
for bi in handler.binary_inputs:
|
|
115
|
+
print(f"BI {bi.index}: {bi.value} (flags={bi.flags.value:#04x})")
|
|
116
|
+
for ai in handler.analog_inputs:
|
|
117
|
+
print(f"AI {ai.index}: {ai.value}")
|
|
118
|
+
|
|
119
|
+
channel.destroy()
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Master - Control Operations
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from dnp3 import OpType, CommandMode
|
|
126
|
+
|
|
127
|
+
# Select-Before-Operate
|
|
128
|
+
channel.select_before_operate(assoc, index=3, op_type=OpType.LATCH_ON)
|
|
129
|
+
|
|
130
|
+
# Direct Operate
|
|
131
|
+
channel.direct_operate(assoc, index=5, op_type=OpType.LATCH_OFF)
|
|
132
|
+
|
|
133
|
+
# Analog output
|
|
134
|
+
channel.operate(
|
|
135
|
+
assoc,
|
|
136
|
+
mode=CommandMode.DIRECT_OPERATE,
|
|
137
|
+
analog_double_commands=[(0, 42.5)],
|
|
138
|
+
)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Outstation Server
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
from dnp3 import Runtime
|
|
145
|
+
from dnp3.outstation import OutstationServer, OutstationConfig
|
|
146
|
+
|
|
147
|
+
with Runtime() as runtime:
|
|
148
|
+
server = OutstationServer(runtime, address="0.0.0.0:20000")
|
|
149
|
+
config = OutstationConfig(outstation_address=10, master_address=1)
|
|
150
|
+
outstation = server.add_outstation(config=config)
|
|
151
|
+
server.bind()
|
|
152
|
+
|
|
153
|
+
# Server is now accepting master connections...
|
|
154
|
+
input("Press Enter to stop")
|
|
155
|
+
server.destroy()
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Examples
|
|
159
|
+
|
|
160
|
+
See the [examples/](examples/) directory for complete working scripts:
|
|
161
|
+
|
|
162
|
+
- [**master_poll.py**](examples/master_poll.py) - Connect and read data points
|
|
163
|
+
- [**master_control.py**](examples/master_control.py) - SBO and direct operate
|
|
164
|
+
- [**master_attributes.py**](examples/master_attributes.py) - Read device attributes (Group 0)
|
|
165
|
+
- [**outstation_server.py**](examples/outstation_server.py) - Test outstation with sample data
|
|
166
|
+
|
|
167
|
+
## API Summary
|
|
168
|
+
|
|
169
|
+
### Core Classes
|
|
170
|
+
|
|
171
|
+
| Class | Description |
|
|
172
|
+
|-------|-------------|
|
|
173
|
+
| `Runtime` | Manages the Tokio async runtime (context manager) |
|
|
174
|
+
| `MasterChannel` | Master station channel with read/control methods |
|
|
175
|
+
| `MasterChannelConfig` | Channel configuration (address, decode level, buffer sizes) |
|
|
176
|
+
| `AssociationConfig` | Association settings (unsolicited, integrity, timeouts) |
|
|
177
|
+
| `ReadHandler` | Collects data from read operations |
|
|
178
|
+
| `OutstationServer` | TCP outstation server for testing |
|
|
179
|
+
|
|
180
|
+
### Channel Factories
|
|
181
|
+
|
|
182
|
+
| Function | Description |
|
|
183
|
+
|----------|-------------|
|
|
184
|
+
| `create_tcp_channel()` | TCP master channel |
|
|
185
|
+
| `create_tls_channel()` | TLS-encrypted master channel |
|
|
186
|
+
| `create_serial_channel()` | Serial port master channel |
|
|
187
|
+
| `create_udp_channel()` | UDP master channel |
|
|
188
|
+
|
|
189
|
+
### Data Types
|
|
190
|
+
|
|
191
|
+
| Type | Description |
|
|
192
|
+
|------|-------------|
|
|
193
|
+
| `BinaryInput` | Binary input point (index, value, flags, timestamp) |
|
|
194
|
+
| `AnalogInput` | Analog input point |
|
|
195
|
+
| `Counter` | Counter point |
|
|
196
|
+
| `BinaryOutputStatus` | Binary output status |
|
|
197
|
+
| `AnalogOutputStatus` | Analog output status |
|
|
198
|
+
| `Group12Var1` | Control Relay Output Block (CROB) |
|
|
199
|
+
| `Variation` | DNP3 group/variation enum |
|
|
200
|
+
|
|
201
|
+
### MasterChannel Methods
|
|
202
|
+
|
|
203
|
+
| Method | Description |
|
|
204
|
+
|--------|-------------|
|
|
205
|
+
| `read()` | One-shot read (by class or variation) |
|
|
206
|
+
| `read_attributes()` | Read device attributes (Group 0) |
|
|
207
|
+
| `add_poll()` | Add periodic poll |
|
|
208
|
+
| `select_before_operate()` | SBO binary output control |
|
|
209
|
+
| `direct_operate()` | Direct operate binary output |
|
|
210
|
+
| `operate()` | Generic control (CROB + analog) |
|
|
211
|
+
| `synchronize_time()` | Time sync (LAN/non-LAN) |
|
|
212
|
+
| `cold_restart()` / `warm_restart()` | Restart commands |
|
|
213
|
+
| `check_link_status()` | Link status check |
|
|
214
|
+
|
|
215
|
+
## Building from Source
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
# 1. Build the Rust library (in a sibling directory)
|
|
219
|
+
git clone https://github.com/stepfunc/dnp3.git ../stepfunc-dnp3
|
|
220
|
+
cd ../stepfunc-dnp3
|
|
221
|
+
cargo build --release -p dnp3-ffi
|
|
222
|
+
|
|
223
|
+
# 2. Install this package
|
|
224
|
+
cd ../dnp3-python
|
|
225
|
+
pip install -e ".[dev]"
|
|
226
|
+
|
|
227
|
+
# 3. Run tests
|
|
228
|
+
pytest tests/
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
This Python wrapper is MIT licensed. See [LICENSE](LICENSE).
|
|
234
|
+
|
|
235
|
+
The underlying stepfunc/dnp3 library uses a non-commercial license
|
|
236
|
+
(evaluation, research, and training use only). See the
|
|
237
|
+
[stepfunc/dnp3 LICENSE](https://github.com/stepfunc/dnp3/blob/main/LICENSE.txt)
|
|
238
|
+
for details.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
dnp3/__init__.py,sha256=7RhCkjj7AAhTa-sXS-KqfXxwNinOAzK2a9u-Hoc32LI,2903
|
|
2
|
+
dnp3/_build_ffi.py,sha256=XKhduO48wQHzAWWxiDGMsYTKGX6fQbODecSbE772oSM,5237
|
|
3
|
+
dnp3/_ffi.py,sha256=8I6Ng1HUgYRmKPrDsY7kAB5D81kJpGv3UZ5Vl29T6Hw,1755
|
|
4
|
+
dnp3/channel.py,sha256=wwyg_ZC4uXD3YJ1HXWpI1kW4ZlbLS2-LOc5lcJ7wIq4,7227
|
|
5
|
+
dnp3/handler.py,sha256=ruGao_Toc-EWqcq1XwbUoz6U24T0BwsVwmheGUraaXQ,17225
|
|
6
|
+
dnp3/logging.py,sha256=a8Jset4GQH3Ks60qNuW7KenhdolT_33udYMLwF4bhX0,2432
|
|
7
|
+
dnp3/master.py,sha256=ggz6sCsXaE1ggVGCrxYAfu5wUTeS8Yzu7lGer-hJGYQ,17773
|
|
8
|
+
dnp3/outstation.py,sha256=pT9OPfm3Zewq05exKnHB0Q2YgckIEfe6He7D8KX4WB0,14977
|
|
9
|
+
dnp3/runtime.py,sha256=ik_f8KKJXsl_we_V5_dhbRoO7p7CFqvwOI5HQ-ZxwSk,1611
|
|
10
|
+
dnp3/types.py,sha256=nJJKplJ62Ij5Njvo6dU-IoP_k-fz5_Oo9odikxjAnAE,11721
|
|
11
|
+
dnp3/vendor/dnp3.h,sha256=UfORDVjFHp9hRXw-nOrc3b2hFYCyaaCIwMs4EueEUnQ,371525
|
|
12
|
+
dnp3/vendor/libdnp3_ffi.so,sha256=JS-a5U3VWn0EDHbT5dUSqpfk7hE_aB8uP7n5-oppcNw,7101512
|
|
13
|
+
pydnp3_stepfunc-1.6.0.3.dist-info/licenses/LICENSE,sha256=rDANftwBo2YLfaPsY4ZKCcHHdQFfpgL1B8GfqE4XIws,1064
|
|
14
|
+
pydnp3_stepfunc-1.6.0.3.dist-info/METADATA,sha256=Tr2ReNKP7oNpRcyhib_4RkgpeX4MvQZ9XQMKZVluZhc,7820
|
|
15
|
+
pydnp3_stepfunc-1.6.0.3.dist-info/WHEEL,sha256=dIWhZP8noP6mB-YKST8g3F1ArFuppNVE7wIphKMromA,104
|
|
16
|
+
pydnp3_stepfunc-1.6.0.3.dist-info/top_level.txt,sha256=Wfb2qiOz-crxcPBaLWFPAzTAt1-9gW6EAitSqdYhIao,5
|
|
17
|
+
pydnp3_stepfunc-1.6.0.3.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 f0rw4rd
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
dnp3
|