Rust library for IEC 60870-5-104 (IEC 104 over TCP): APDUs, ASDUs, type IDs, and async I/O on Tokio. The focus is balanced (station-to-station) communication as used in energy and automation SCADA.
Status: usable for client work, low-level servers, and the bundled RTU-style server layer, but the API and behavior are still evolving. Report issues and try the examples before relying on it in production.
| Area | Module | Role |
|---|---|---|
| Client | iec104::client |
Connect to a remote IEC 104 station, send commands, receive ASDUs via ClientCallback. Optional TLS is configured on ClientConfig (TlsClientConfig). |
| Server (low level) | iec104::server |
Accept TCP connections, run the 104 link layer (STARTDT / TESTFR / …), decode ingress ASDUs, and deliver them to your ServerCallback. You implement all application logic (interrogations, spontaneous data, command handling). TLS is optional via ServerConfig / TlsServerConfig. |
| RTU server (high level) | iec104::rtu_server |
In-memory typed points, general and group interrogation, counter interrogation, pluggable process commands (RtuCommandHandler), and default system ASDUs (clock sync, test, read, reset process, etc.). Built on the low-level Server. |
| Types & parsing | iec104::types, iec104::asdu, iec104::types_id |
ASDU building blocks, information objects, and type IDs used by client and server paths. |
This is IEC 60870-5-104 only (not 101 serial profiles). File transfer, integrated totals beyond what the RTU layer models, and every optional standard feature are not goals for v1 completeness—check TypeId and module docs for what is encoded and parsed today.
Build and run from the repository root:
cargo run --example client
cargo run --example server
cargo run --example rtu_server| Example | Description |
|---|---|
examples/client.rs |
Minimal master/client: connect, start receiving, demonstrate sending a process command. |
examples/server.rs |
Minimal slave/server callback: accept connections and react to incoming ASDUs yourself. |
examples/rtu_server.rs |
RTU-style station with a documented point table (common address 47), interrogation, counter interrogation, clock sync, and command presets—intended for learning and for the Python harness below. |
End-to-end checks against examples/rtu_server live under tests/:
tests/run_rtu_e2e.sh— builds the example, starts it, runstests/test_client.py.- The script expects the iec104-python module (
c104) in the environment (for example the project.venv; see comments in the shell script).
The RTU example is aligned with that client for general interrogation, clock sync, counter interrogation, group interrogation, C_TS_TA_1 test command, and process commands. Note: interoperability always depends on both stacks’ choices (type IDs, COTs, timeouts).
| Feature | Default | Effect |
|---|---|---|
chrono |
yes | Conversions between IEC time tags (Cp24Time2a, Cp56Time2a) and chrono DateTime (disable default features with default-features = false if you do not want the dependency). |
- Rust with support for the edition and features declared in
Cargo.toml(currently Edition 2024). - Tokio runtime for async networking.
- Work in progress: public APIs and default RTU behavior may change between minor releases until the crate stabilises.
- Coverage: not every standard type ID or edge case is implemented or battle-tested; prefer explicit tests for your IO list.
- Low-level
Server: does not implement an RTU process image—you get raw ASDUs and must send replies yourself. - Security: TLS is available for transport; application-layer security (authentication, authorisation) is outside IEC 104 and not provided here.
- 101 / serial: out of scope.
Contributions are welcome and encouraged. Please run tests and formatters locally before opening a pull request.
Hooks are optional but useful for consistent style:
- Install pre-commit (package manager or
pip install --user pre-commit). pre-commit autoupdate— refresh hook revisions.pre-commit install— enable hooks in this clone.