profinet-py 0.6.0__tar.gz → 0.6.2__tar.gz

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.
Files changed (45) hide show
  1. profinet_py-0.6.2/LICENSE-COMMERCIAL.md +28 -0
  2. {profinet_py-0.6.0/profinet_py.egg-info → profinet_py-0.6.2}/PKG-INFO +25 -42
  3. {profinet_py-0.6.0 → profinet_py-0.6.2}/README.md +15 -33
  4. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/__init__.py +2 -6
  5. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/alarm_listener.py +2 -2
  6. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/cli.py +38 -2
  7. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/dcp.py +8 -11
  8. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/gsdml.py +2 -2
  9. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/protocol.py +0 -3
  10. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/rpc.py +0 -3
  11. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/util.py +13 -312
  12. {profinet_py-0.6.0 → profinet_py-0.6.2/profinet_py.egg-info}/PKG-INFO +25 -42
  13. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet_py.egg-info/SOURCES.txt +2 -0
  14. profinet_py-0.6.2/profinet_py.egg-info/requires.txt +9 -0
  15. {profinet_py-0.6.0 → profinet_py-0.6.2}/pyproject.toml +20 -20
  16. profinet_py-0.6.2/tests/test_cyclic_hw.py +466 -0
  17. {profinet_py-0.6.0 → profinet_py-0.6.2}/tests/test_rpc.py +109 -0
  18. {profinet_py-0.6.0 → profinet_py-0.6.2}/tests/test_util.py +64 -0
  19. profinet_py-0.6.0/profinet_py.egg-info/requires.txt +0 -8
  20. {profinet_py-0.6.0 → profinet_py-0.6.2}/LICENSE +0 -0
  21. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/alarms.py +0 -0
  22. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/blocks.py +0 -0
  23. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/cyclic.py +0 -0
  24. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/device.py +0 -0
  25. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/diagnosis.py +0 -0
  26. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/exceptions.py +0 -0
  27. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/indices.py +0 -0
  28. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/py.typed +0 -0
  29. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/rt.py +0 -0
  30. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet/vendors.py +0 -0
  31. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet_py.egg-info/dependency_links.txt +0 -0
  32. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet_py.egg-info/entry_points.txt +0 -0
  33. {profinet_py-0.6.0 → profinet_py-0.6.2}/profinet_py.egg-info/top_level.txt +0 -0
  34. {profinet_py-0.6.0 → profinet_py-0.6.2}/setup.cfg +0 -0
  35. {profinet_py-0.6.0 → profinet_py-0.6.2}/tests/test_alarm_listener.py +0 -0
  36. {profinet_py-0.6.0 → profinet_py-0.6.2}/tests/test_blocks.py +0 -0
  37. {profinet_py-0.6.0 → profinet_py-0.6.2}/tests/test_cyclic.py +0 -0
  38. {profinet_py-0.6.0 → profinet_py-0.6.2}/tests/test_dcp.py +0 -0
  39. {profinet_py-0.6.0 → profinet_py-0.6.2}/tests/test_diagnosis.py +0 -0
  40. {profinet_py-0.6.0 → profinet_py-0.6.2}/tests/test_exceptions.py +0 -0
  41. {profinet_py-0.6.0 → profinet_py-0.6.2}/tests/test_gsdml.py +0 -0
  42. {profinet_py-0.6.0 → profinet_py-0.6.2}/tests/test_indices.py +0 -0
  43. {profinet_py-0.6.0 → profinet_py-0.6.2}/tests/test_protocol.py +0 -0
  44. {profinet_py-0.6.0 → profinet_py-0.6.2}/tests/test_review_fixes.py +0 -0
  45. {profinet_py-0.6.0 → profinet_py-0.6.2}/tests/test_rt.py +0 -0
@@ -0,0 +1,28 @@
1
+ # Commercial License — profinet-py
2
+
3
+ This software is dual-licensed:
4
+
5
+ - **Open source** under the [GNU General Public License v3.0](LICENSE) for free and
6
+ open source use.
7
+ - **Commercial/OEM license** for use in proprietary products, described below.
8
+
9
+ ## When you need a commercial license
10
+
11
+ A commercial license is required if you want to:
12
+
13
+ - Embed profinet-py in proprietary software or hardware products
14
+ - Distribute profinet-py as part of a closed-source application
15
+ - Use profinet-py in a product without complying with GPL-3.0 obligations
16
+ (source disclosure, copyleft, license notices)
17
+
18
+ ## What the commercial license provides
19
+
20
+ - Permission to use, modify, and distribute profinet-py in proprietary products
21
+ - No requirement to disclose your source code
22
+ - No copyleft obligations
23
+ - Priority support options available
24
+
25
+ ## Contact
26
+
27
+ For commercial licensing inquiries, contact the maintainer via the details listed
28
+ at <https://github.com/f0rw4rd>.
@@ -1,14 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: profinet-py
3
- Version: 0.6.0
3
+ Version: 0.6.2
4
4
  Summary: PROFINET IO-Controller library for Python
5
5
  Author: f0rw4rd
6
6
  Maintainer: f0rw4rd
7
7
  License-Expression: GPL-3.0-only
8
- Project-URL: Homepage, https://github.com/f0rw4rd/profinet
9
- Project-URL: Repository, https://github.com/f0rw4rd/profinet
10
- Project-URL: Original Project, https://github.com/alfredkrohmer/profinet
11
- Project-URL: Issues, https://github.com/f0rw4rd/profinet/issues
8
+ Project-URL: Homepage, https://github.com/f0rw4rd/profinet-py
9
+ Project-URL: Repository, https://github.com/f0rw4rd/profinet-py
10
+ Project-URL: Issues, https://github.com/f0rw4rd/profinet-py/issues
12
11
  Keywords: profinet,industrial,ics,ot,plc,automation,siemens,dcp,rpc
13
12
  Classifier: Development Status :: 4 - Beta
14
13
  Classifier: Environment :: Console
@@ -23,17 +22,26 @@ Classifier: Typing :: Typed
23
22
  Requires-Python: >=3.10
24
23
  Description-Content-Type: text/markdown
25
24
  License-File: LICENSE
25
+ License-File: LICENSE-COMMERCIAL.md
26
26
  Requires-Dist: construct>=2.10
27
27
  Provides-Extra: dev
28
- Requires-Dist: pytest>=7.0; extra == "dev"
28
+ Requires-Dist: pytest>=9.0.0; extra == "dev"
29
29
  Requires-Dist: pytest-cov>=4.0; extra == "dev"
30
- Requires-Dist: black>=23.0; extra == "dev"
31
- Requires-Dist: mypy>=1.0; extra == "dev"
32
- Requires-Dist: ruff>=0.1.0; extra == "dev"
30
+ Requires-Dist: ruff>=0.15.0; extra == "dev"
31
+ Requires-Dist: vulture>=2.14; extra == "dev"
32
+ Requires-Dist: bandit>=1.9.3; extra == "dev"
33
+ Requires-Dist: pre-commit>=4.0.0; extra == "dev"
33
34
  Dynamic: license-file
34
35
 
35
36
  # profinet-py
36
37
 
38
+ [![CI](https://github.com/f0rw4rd/profinet-py/actions/workflows/ci.yml/badge.svg)](https://github.com/f0rw4rd/profinet-py/actions/workflows/ci.yml)
39
+ [![PyPI](https://img.shields.io/pypi/v/profinet-py)](https://pypi.org/project/profinet-py/)
40
+ [![Python](https://img.shields.io/pypi/pyversions/profinet-py)](https://pypi.org/project/profinet-py/)
41
+ [![License](https://img.shields.io/github/license/f0rw4rd/profinet-py)](LICENSE)
42
+ [![Code style: ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
43
+ [![CLA](https://img.shields.io/badge/CLA-required-blue)](CONTRIBUTING.md)
44
+
37
45
  A Python library for PROFINET IO communication, acting as an IO-Controller.
38
46
 
39
47
  ## Features
@@ -46,7 +54,7 @@ A Python library for PROFINET IO communication, acting as an IO-Controller.
46
54
  - **Diagnosis Parsing**: Channel, extended channel, and qualified channel diagnosis decoding
47
55
  - **Vendor Registry**: 2100+ PROFINET vendor IDs with name lookup
48
56
  - **Declarative Parsing**: Binary protocol parsing via [construct](https://construct.readthedocs.io/) library
49
- - **Cross-Platform**: Linux (AF_PACKET), Windows (Npcap), macOS (libpcap)
57
+ - **Cross-Platform**: Linux (AF_PACKET), Windows (Npcap)
50
58
  - **High-level API**: `ProfinetDevice` class and `scan()` for quick device interaction
51
59
 
52
60
  ## Requirements
@@ -61,7 +69,6 @@ A Python library for PROFINET IO communication, acting as an IO-Controller.
61
69
  |----------|-------------------|----------------|
62
70
  | **Linux** | AF_PACKET (built-in) | None |
63
71
  | **Windows** | Npcap (wpcap.dll) | Install [Npcap](https://npcap.com/) with "WinPcap API-compatible Mode" enabled |
64
- | **macOS** | libpcap (built-in) | None |
65
72
 
66
73
  ## Installation
67
74
 
@@ -72,8 +79,8 @@ pip install profinet-py
72
79
  From source:
73
80
 
74
81
  ```bash
75
- git clone https://github.com/f0rw4rd/profinet.git
76
- cd profinet
82
+ git clone https://github.com/f0rw4rd/profinet-py.git
83
+ cd profinet-py
77
84
  pip install -e ".[dev]"
78
85
  ```
79
86
 
@@ -131,34 +138,6 @@ profinet -i eth0 cyclic device-name --gsdml device.xml
131
138
  profinet -i eth0 cyclic device-name --gsdml device.xml --cycle-ms 16
132
139
  ```
133
140
 
134
- ## Credits
135
-
136
- This project is a modernized fork of the original PROFINET library by **Alfred Krohmer**:
137
-
138
- - **Original Repository**: https://github.com/alfredkrohmer/profinet
139
- - **Original Author**: Alfred Krohmer (2015)
140
-
141
- ### Changes in this fork
142
-
143
- - Cross-platform support (Windows via Npcap ctypes, macOS via libpcap ctypes)
144
- - Dropped Python 3.8/3.9 (EOL), targets Python 3.10+
145
- - Migrated all binary parsing from `struct` to `construct` library for declarative, readable protocol definitions
146
- - Fixed 5 protocol bugs verified against Wireshark's PROFINET dissector and IEC 61158-6-10:
147
- - DCP Option 0x04 is Reserved (not LLDP)
148
- - Block Type 0x0012 is ExpectedIdentificationData (not QualifiedChannelDiagnosis)
149
- - RT_CLASS_1 frame ID range starts at 0x8000 (not 0xC000)
150
- - Device Suboption 0x09 does not exist in the spec
151
- - DCP Identify uses separate Frame IDs for request (0xFEFE) and response (0xFEFF)
152
- - DCP SET operations now validate response block error codes instead of silently succeeding
153
- - Diagnosis parsing module with channel/extended/qualified channel support
154
- - Alarm notification parsing and background alarm listener
155
- - Cyclic I/O controller for RT_CLASS_1 periodic data exchange with explicit state machine (`IDLE → RUNNING → STOPPING → STOPPED`, `FAULT`), double-buffered output data, per-frame cycle counter tracking (gap/duplicate/out-of-order detection), watchdog with automatic fault transition, IOCS consumer status handling, graceful stop (RUN→STOP frames), and separate TX/RX sockets
156
- - High-level `ProfinetDevice` API with `start_cyclic()` for integrated cyclic IO, plus `scan()`/`scan_dict()` convenience functions
157
- - 2100+ vendor ID registry with lookup
158
- - CLI tool for discovery, I&M reading, and raw record access
159
- - 700+ unit tests, Docker-based integration tests against p-net device emulator
160
- - Type hints, ruff linting, mypy checking
161
-
162
141
  ## Support
163
142
 
164
143
  If you find this project useful, consider supporting development:
@@ -167,7 +146,11 @@ If you find this project useful, consider supporting development:
167
146
 
168
147
  ## License
169
148
 
170
- GPLv3. See [LICENSE](LICENSE) for details.
149
+ Dual-licensed under [GPL-3.0](LICENSE) and a [commercial license](LICENSE-COMMERCIAL.md).
150
+
151
+ Free for open source use under GPL-3.0. If you want to use profinet-py in proprietary
152
+ products without GPL obligations, a commercial license is available —
153
+ see [LICENSE-COMMERCIAL.md](LICENSE-COMMERCIAL.md) for details.
171
154
 
172
155
  ## References
173
156
 
@@ -1,5 +1,12 @@
1
1
  # profinet-py
2
2
 
3
+ [![CI](https://github.com/f0rw4rd/profinet-py/actions/workflows/ci.yml/badge.svg)](https://github.com/f0rw4rd/profinet-py/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/profinet-py)](https://pypi.org/project/profinet-py/)
5
+ [![Python](https://img.shields.io/pypi/pyversions/profinet-py)](https://pypi.org/project/profinet-py/)
6
+ [![License](https://img.shields.io/github/license/f0rw4rd/profinet-py)](LICENSE)
7
+ [![Code style: ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
8
+ [![CLA](https://img.shields.io/badge/CLA-required-blue)](CONTRIBUTING.md)
9
+
3
10
  A Python library for PROFINET IO communication, acting as an IO-Controller.
4
11
 
5
12
  ## Features
@@ -12,7 +19,7 @@ A Python library for PROFINET IO communication, acting as an IO-Controller.
12
19
  - **Diagnosis Parsing**: Channel, extended channel, and qualified channel diagnosis decoding
13
20
  - **Vendor Registry**: 2100+ PROFINET vendor IDs with name lookup
14
21
  - **Declarative Parsing**: Binary protocol parsing via [construct](https://construct.readthedocs.io/) library
15
- - **Cross-Platform**: Linux (AF_PACKET), Windows (Npcap), macOS (libpcap)
22
+ - **Cross-Platform**: Linux (AF_PACKET), Windows (Npcap)
16
23
  - **High-level API**: `ProfinetDevice` class and `scan()` for quick device interaction
17
24
 
18
25
  ## Requirements
@@ -27,7 +34,6 @@ A Python library for PROFINET IO communication, acting as an IO-Controller.
27
34
  |----------|-------------------|----------------|
28
35
  | **Linux** | AF_PACKET (built-in) | None |
29
36
  | **Windows** | Npcap (wpcap.dll) | Install [Npcap](https://npcap.com/) with "WinPcap API-compatible Mode" enabled |
30
- | **macOS** | libpcap (built-in) | None |
31
37
 
32
38
  ## Installation
33
39
 
@@ -38,8 +44,8 @@ pip install profinet-py
38
44
  From source:
39
45
 
40
46
  ```bash
41
- git clone https://github.com/f0rw4rd/profinet.git
42
- cd profinet
47
+ git clone https://github.com/f0rw4rd/profinet-py.git
48
+ cd profinet-py
43
49
  pip install -e ".[dev]"
44
50
  ```
45
51
 
@@ -97,34 +103,6 @@ profinet -i eth0 cyclic device-name --gsdml device.xml
97
103
  profinet -i eth0 cyclic device-name --gsdml device.xml --cycle-ms 16
98
104
  ```
99
105
 
100
- ## Credits
101
-
102
- This project is a modernized fork of the original PROFINET library by **Alfred Krohmer**:
103
-
104
- - **Original Repository**: https://github.com/alfredkrohmer/profinet
105
- - **Original Author**: Alfred Krohmer (2015)
106
-
107
- ### Changes in this fork
108
-
109
- - Cross-platform support (Windows via Npcap ctypes, macOS via libpcap ctypes)
110
- - Dropped Python 3.8/3.9 (EOL), targets Python 3.10+
111
- - Migrated all binary parsing from `struct` to `construct` library for declarative, readable protocol definitions
112
- - Fixed 5 protocol bugs verified against Wireshark's PROFINET dissector and IEC 61158-6-10:
113
- - DCP Option 0x04 is Reserved (not LLDP)
114
- - Block Type 0x0012 is ExpectedIdentificationData (not QualifiedChannelDiagnosis)
115
- - RT_CLASS_1 frame ID range starts at 0x8000 (not 0xC000)
116
- - Device Suboption 0x09 does not exist in the spec
117
- - DCP Identify uses separate Frame IDs for request (0xFEFE) and response (0xFEFF)
118
- - DCP SET operations now validate response block error codes instead of silently succeeding
119
- - Diagnosis parsing module with channel/extended/qualified channel support
120
- - Alarm notification parsing and background alarm listener
121
- - Cyclic I/O controller for RT_CLASS_1 periodic data exchange with explicit state machine (`IDLE → RUNNING → STOPPING → STOPPED`, `FAULT`), double-buffered output data, per-frame cycle counter tracking (gap/duplicate/out-of-order detection), watchdog with automatic fault transition, IOCS consumer status handling, graceful stop (RUN→STOP frames), and separate TX/RX sockets
122
- - High-level `ProfinetDevice` API with `start_cyclic()` for integrated cyclic IO, plus `scan()`/`scan_dict()` convenience functions
123
- - 2100+ vendor ID registry with lookup
124
- - CLI tool for discovery, I&M reading, and raw record access
125
- - 700+ unit tests, Docker-based integration tests against p-net device emulator
126
- - Type hints, ruff linting, mypy checking
127
-
128
106
  ## Support
129
107
 
130
108
  If you find this project useful, consider supporting development:
@@ -133,7 +111,11 @@ If you find this project useful, consider supporting development:
133
111
 
134
112
  ## License
135
113
 
136
- GPLv3. See [LICENSE](LICENSE) for details.
114
+ Dual-licensed under [GPL-3.0](LICENSE) and a [commercial license](LICENSE-COMMERCIAL.md).
115
+
116
+ Free for open source use under GPL-3.0. If you want to use profinet-py in proprietary
117
+ products without GPL obligations, a commercial license is available —
118
+ see [LICENSE-COMMERCIAL.md](LICENSE-COMMERCIAL.md) for details.
137
119
 
138
120
  ## References
139
121
 
@@ -9,12 +9,8 @@ A Python library for PROFINET IO communication, supporting:
9
9
  This library acts as an IO-Controller, allowing connection to and
10
10
  communication with PROFINET IO-Devices.
11
11
 
12
- Credits:
13
- Original implementation by Alfred Krohmer (2015)
14
- https://github.com/alfredkrohmer/profinet
15
-
16
- Modernized for Python 3.8+ by f0rw4rd (2024)
17
- https://github.com/f0rw4rd/profinet-py
12
+ Author: f0rw4rd
13
+ https://github.com/f0rw4rd/profinet-py
18
14
  """
19
15
 
20
16
  from . import blocks, indices
@@ -194,7 +194,7 @@ class AlarmListener:
194
194
  Returns:
195
195
  Configured socket for alarm reception.
196
196
  For Layer 2: platform-abstracted raw socket (AF_PACKET on Linux,
197
- NpcapSocket on Windows, PcapSocket on macOS).
197
+ NpcapSocket on Windows).
198
198
  For UDP: standard socket.
199
199
 
200
200
  Raises:
@@ -210,7 +210,7 @@ class AlarmListener:
210
210
  # UDP socket (port 34964) — works on all platforms
211
211
  sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
212
212
  sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
213
- sock.bind(("0.0.0.0", 34964))
213
+ sock.bind(("0.0.0.0", 34964)) # nosec B104 — must receive from any interface
214
214
 
215
215
  # Non-blocking timeout for clean shutdown
216
216
  sock.settimeout(1.0)
@@ -1,7 +1,6 @@
1
1
  """
2
2
  PROFINET command-line interface.
3
3
 
4
- Credits: Original implementation by Alfred Krohmer (2015)
5
4
  """
6
5
 
7
6
  from __future__ import annotations
@@ -141,6 +140,31 @@ def cmd_read(args: argparse.Namespace) -> int:
141
140
  sock.close()
142
141
 
143
142
 
143
+ def cmd_write(args: argparse.Namespace) -> int:
144
+ """Execute write command."""
145
+ sock = ethernet_socket(args.interface, 3)
146
+ try:
147
+ src = get_mac(args.interface)
148
+
149
+ print(f"Connecting to {args.target}...")
150
+ info = rpc.get_station_info(sock, src, args.target)
151
+
152
+ with rpc.RPCCon(info) as conn:
153
+ conn.connect(src)
154
+
155
+ idx = int(args.index, 16) if args.index.startswith("0x") else int(args.index)
156
+ data = bytes.fromhex(args.data.replace(" ", ""))
157
+ conn.write(api=args.api, slot=args.slot, subslot=args.subslot, idx=idx, data=data)
158
+
159
+ print(
160
+ f"Wrote {len(data)} bytes to slot={args.slot} subslot={args.subslot} index=0x{idx:04X}"
161
+ )
162
+
163
+ return 0
164
+ finally:
165
+ sock.close()
166
+
167
+
144
168
  def cmd_read_inm0_filter(args: argparse.Namespace) -> int:
145
169
  """Execute read-inm0-filter command."""
146
170
  sock = ethernet_socket(args.interface, 3)
@@ -574,7 +598,7 @@ def create_parser() -> argparse.ArgumentParser:
574
598
  parser = argparse.ArgumentParser(
575
599
  prog="profinet",
576
600
  description="PROFINET IO-Controller CLI",
577
- epilog="Credits: Original implementation by Alfred Krohmer (2015)",
601
+ epilog="https://github.com/f0rw4rd/profinet-py",
578
602
  )
579
603
 
580
604
  parser.add_argument(
@@ -631,6 +655,18 @@ def create_parser() -> argparse.ArgumentParser:
631
655
  sub.add_argument("--index", required=True, help="Record index (hex with 0x prefix)")
632
656
  sub.set_defaults(func=cmd_read)
633
657
 
658
+ # write
659
+ sub = subparsers.add_parser("write", help="Write data record")
660
+ sub.add_argument("target", metavar="NAME", help="Station name (e.g. my-device)")
661
+ sub.add_argument("--api", type=int, default=0, help="API (default: 0)")
662
+ sub.add_argument("--slot", type=int, required=True, help="Slot number")
663
+ sub.add_argument("--subslot", type=int, required=True, help="Subslot number")
664
+ sub.add_argument(
665
+ "--index", required=True, help="Record index (hex with 0x prefix, e.g. 0xAFF1)"
666
+ )
667
+ sub.add_argument("data", metavar="HEX", help="Data to write as hex string (e.g. deadbeef)")
668
+ sub.set_defaults(func=cmd_write)
669
+
634
670
  # read-inm0-filter
635
671
  sub = subparsers.add_parser("read-inm0-filter", help="Read device topology")
636
672
  sub.add_argument("target", metavar="NAME", help="Station name (e.g. my-device)")
@@ -7,15 +7,12 @@ Provides device discovery and basic configuration operations:
7
7
  - get_param(): Read device parameter (name, IP)
8
8
  - set_param(): Write device parameter
9
9
 
10
- Credits:
11
- Original implementation by Alfred Krohmer (2015)
12
- https://github.com/alfredkrohmer/profinet
13
10
  """
14
11
 
15
12
  from __future__ import annotations
16
13
 
17
14
  import logging
18
- import random
15
+ import secrets
19
16
  import time
20
17
  from collections.abc import Callable
21
18
  from dataclasses import dataclass
@@ -507,7 +504,7 @@ PARAMS: Dict[str, Tuple[int, int]] = {
507
504
 
508
505
  def _generate_xid() -> int:
509
506
  """Generate random transaction ID for DCP requests."""
510
- return random.randint(0, 0xFFFFFFFF)
507
+ return secrets.randbelow(0x100000000)
511
508
 
512
509
 
513
510
  # =============================================================================
@@ -587,9 +584,9 @@ class DCPDeviceDescription:
587
584
  self.netmask = s2ip(ip_block[6:10])
588
585
  self.gateway = s2ip(ip_block[10:14])
589
586
  else:
590
- self.ip = "0.0.0.0"
591
- self.netmask = "0.0.0.0"
592
- self.gateway = "0.0.0.0"
587
+ self.ip = "0.0.0.0" # nosec B104 — PROFINET default (no IP assigned)
588
+ self.netmask = "0.0.0.0" # nosec B104
589
+ self.gateway = "0.0.0.0" # nosec B104
593
590
  logger.warning(f"Device {self.mac} has no IP configuration")
594
591
 
595
592
  # Handle device ID (optional)
@@ -1335,9 +1332,9 @@ def send_hello(
1335
1332
  sock: socket,
1336
1333
  src: bytes,
1337
1334
  station_name: str,
1338
- ip: str = "0.0.0.0",
1339
- netmask: str = "0.0.0.0",
1340
- gateway: str = "0.0.0.0",
1335
+ ip: str = "0.0.0.0", # nosec B104 — PROFINET default (no IP assigned)
1336
+ netmask: str = "0.0.0.0", # nosec B104
1337
+ gateway: str = "0.0.0.0", # nosec B104
1341
1338
  device_id: Tuple[int, int] = (0, 0),
1342
1339
  device_role: int = DEVICE_ROLE_IO_DEVICE,
1343
1340
  ) -> None:
@@ -7,7 +7,7 @@ module/submodule IDs and IO data sizes.
7
7
 
8
8
  from __future__ import annotations
9
9
 
10
- import xml.etree.ElementTree as ET
10
+ import xml.etree.ElementTree as ET # nosec B405 — GSDML files are local trusted vendor data
11
11
  from dataclasses import dataclass, field
12
12
  from pathlib import Path
13
13
  from typing import Dict, List, Optional, Union
@@ -503,7 +503,7 @@ def load_gsdml(path: Union[str, Path]) -> GSDMLDevice:
503
503
  Returns:
504
504
  GSDMLDevice with full module catalog.
505
505
  """
506
- tree = ET.parse(str(path))
506
+ tree = ET.parse(str(path)) # nosec B314 — GSDML files are local trusted vendor data
507
507
  return _parse_gsdml_root(tree.getroot())
508
508
 
509
509
 
@@ -6,9 +6,6 @@ Defines packet structures for:
6
6
  - DCE/RPC (Remote Procedure Call)
7
7
  - PNIO (PROFINET IO) data blocks
8
8
 
9
- Credits:
10
- Original implementation by Alfred Krohmer (2015)
11
- https://github.com/alfredkrohmer/profinet
12
9
  """
13
10
 
14
11
  from __future__ import annotations
@@ -6,9 +6,6 @@ Provides IO-Controller functionality:
6
6
  - get_station_info(): Resolve device name to connection info
7
7
  - Read/Write operations via slot/subslot/index addressing
8
8
 
9
- Credits:
10
- Original implementation by Alfred Krohmer (2015)
11
- https://github.com/alfredkrohmer/profinet
12
9
  """
13
10
 
14
11
  from __future__ import annotations