snap7-client 0.1.2

Async Rust client for Siemens S7 PLCs over ISO-on-TCP (S7Comm and S7CommPlus)
Documentation

snap7-client

Async Rust client for Siemens S7 PLCs over ISO-on-TCP. Pure Rust — no FFI, no native C dependency.

Part of the rs-snap7 workspace.

Features

  • S7Client — async read/write for S7-300/400/1200/1500 via S7Comm
  • S7PlusClient — S7CommPlus (S7-1200/1500 newer firmware)
  • S7Pool — bounded connection pool with RAII checkout
  • Multi-read / multi-write — batched PDU packing, automatic splitting at PDU limit
  • Typed tag access — DB1,REAL4, DB70,332.0 (bit), DB1,INT8, etc.
  • TLS transport — encrypted S7CommPlus via tokio-rustls
  • UDP transport
  • sync feature — blocking wrapper around the async client

Add to your project

[dependencies]
snap7-client = "0.1"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

Quick start

Single connection

use snap7_client::{S7Client, ConnectParams};
use snap7_client::transport::TcpTransport;
use std::net::SocketAddr;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let addr: SocketAddr = "192.168.1.100:102".parse()?;
    let params = ConnectParams { rack: 0, slot: 1, ..Default::default() };
    let client = S7Client::<TcpTransport>::connect(addr, params).await?;

    // Read 4 bytes from DB1 at offset 0
    let data = client.db_read(1, 0, 4).await?;
    println!("{data:x?}");

    // Write bytes
    client.db_write(1, 0, &[0xDE, 0xAD, 0xBE, 0xEF]).await?;

    Ok(())
}

Multi-read (single PDU round-trip)

use snap7_client::MultiReadItem;

let items = vec![
    MultiReadItem::db(1, 0, 4),   // DB1, offset 0, 4 bytes
    MultiReadItem::db(2, 10, 2),  // DB2, offset 10, 2 bytes
];
let results = client.read_multi_vars(&items).await?;
// results[0] and results[1] — automatically batched across PDUs when needed

Connection pool

use snap7_client::{S7Pool, PoolConfig, ConnectParams};
use std::net::SocketAddr;

let pool = S7Pool::new(
    "192.168.1.100:102".parse()?,
    ConnectParams::default(),
    PoolConfig { max_size: 4, ..Default::default() },
);

let guard = pool.acquire().await?;
guard.client().db_read(1, 0, 4).await?;
// connection returned to pool on drop

Typed tag read/write

use snap7_client::tag::parse_tag;

let tag = parse_tag("DB1,REAL4")?;   // REAL at byte offset 4
let tag = parse_tag("DB1,DINT0")?;
let tag = parse_tag("DB70,332.0")?;  // bit 0 of byte 332

TLS (S7CommPlus encrypted)

use snap7_client::tls::tls_connect;

let stream = tls_connect("plc.example.com", 102, None).await?;
let client = S7Client::from_transport(stream, ConnectParams::default()).await?;

Sync (blocking) API

Enable the sync feature and use snap7_client::client_sync::S7ClientSync.

snap7-client = { version = "0.1", features = ["sync"] }

Tag address syntax

DB<n>,<type><byte-offset>
DB<n>,<byte-offset>.<bit>
Type Width Example
REAL 4 B DB1,REAL0
DINT 4 B DB1,DINT4
DWORD 4 B DB1,DWORD4
INT 2 B DB1,INT8
WORD 2 B DB1,WORD8
BYTE 1 B DB1,BYTE10
bit 1 bit DB1,332.0

License

MIT — see LICENSE.