Skip to main content

EipClient

Struct EipClient 

Source
pub struct EipClient { /* private fields */ }
Expand description

High-performance EtherNet/IP client for PLC communication

This struct provides the core functionality for communicating with Allen-Bradley PLCs using the EtherNet/IP protocol. It handles connection management, session registration, and tag operations.

§Thread Safety

The EipClient is NOT thread-safe. For multi-threaded applications:

use std::sync::Arc;
use tokio::sync::Mutex;
use rust_ethernet_ip::EipClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    // Create a thread-safe wrapper
    let client = Arc::new(Mutex::new(EipClient::connect("192.168.1.100:44818").await?));

    // Use in multiple threads
    let client_clone = client.clone();
    tokio::spawn(async move {
        let mut client = client_clone.lock().await;
        let _ = client.read_tag("Tag1").await?;
        Ok::<(), Box<dyn std::error::Error + Send + Sync>>(())
    });
    Ok(())
}

§Performance Characteristics

OperationLatencyThroughputMemory
Connect100-500msN/A~8KB
Read Tag1-5ms1,500+ ops/sec~2KB
Write Tag2-10ms600+ ops/sec~2KB
Batch Read5-20ms2,000+ ops/sec~4KB

§Known Limitations

The following operations are not supported due to PLC firmware limitations:

§UDT Array Element Member Writes

Cannot write directly to UDT array element members (e.g., gTestUDT_Array[0].Member1_DINT). This is a PLC firmware limitation, not a library bug. The PLC returns CIP Error 0x2107 (Vendor Specific Error) when attempting to write to such paths.

§STRING Tags and STRING Members in UDTs

Cannot write directly to STRING tags or STRING members in UDTs. This is a PLC firmware limitation (CIP Error 0x2107). Both simple STRING tags (e.g., gTest_STRING) and STRING members within UDTs (e.g., gTestUDT.Member5_String) cannot be written directly. STRING values must be written as part of the entire UDT structure, not as individual tags or members.

What works:

  • ✅ Reading UDT array element members: gTestUDT_Array[0].Member1_DINT (read)
  • ✅ Writing entire UDT array elements: gTestUDT_Array[0] (write full UDT)
  • ✅ Writing UDT members (non-STRING): gTestUDT.Member1_DINT (write DINT/REAL/BOOL/INT members)
  • ✅ Writing array elements: gArray[5] (write element of simple array)
  • ✅ Reading STRING tags: gTest_STRING (read)
  • ✅ Reading STRING members in UDTs: gTestUDT.Member5_String (read)

What doesn’t work:

  • ❌ Writing UDT array element members: gTestUDT_Array[0].Member1_DINT (write)
  • ❌ Writing program-scoped UDT array element members: Program:TestProgram.gTestUDT_Array[0].Member1_DINT (write)
  • ❌ Writing simple STRING tags: gTest_STRING (write) - PLC limitation
  • ❌ Writing program-scoped STRING tags: Program:TestProgram.gTest_STRING (write) - PLC limitation
  • ❌ Writing STRING members in UDTs: gTestUDT.Member5_String (write) - must write entire UDT
  • ❌ Writing program-scoped STRING members: Program:TestProgram.gTestUDT.Member5_String (write) - must write entire UDT

Workaround: To modify a UDT array element member, read the entire UDT array element, modify the member in memory, then write the entire UDT array element back:

use rust_ethernet_ip::{PlcValue, UdtData};

// Read the entire UDT array element
let udt_value = client.read_tag("gTestUDT_Array[0]").await?;
if let PlcValue::Udt(mut udt_data) = udt_value {
    let udt_def = client.get_udt_definition("gTestUDT_Array").await?;
    // Convert UdtDefinition to UserDefinedType
    let mut user_def = rust_ethernet_ip::udt::UserDefinedType::new(udt_def.name.clone());
    for member in &udt_def.members {
        user_def.add_member(member.clone());
    }
    let mut members = udt_data.parse(&user_def)?;
     
    // Modify the member
    members.insert("Member1_DINT".to_string(), PlcValue::Dint(100));
     
    // Write the entire UDT array element back
    let modified_udt = UdtData::from_hash_map(&members, &user_def, udt_data.symbol_id)?;
    client.write_tag("gTestUDT_Array[0]", PlcValue::Udt(modified_udt)).await?;
}

§Error Handling

All operations return Result<T, EtherNetIpError>. Common errors include:

use rust_ethernet_ip::{EipClient, EtherNetIpError};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let mut client = EipClient::connect("192.168.1.100:44818").await?;
    match client.read_tag("Tag1").await {
        Ok(value) => println!("Tag value: {:?}", value),
        Err(EtherNetIpError::Protocol(_)) => println!("Tag does not exist"),
        Err(EtherNetIpError::Connection(_)) => println!("Lost connection to PLC"),
        Err(EtherNetIpError::Timeout(_)) => println!("Operation timed out"),
        Err(e) => println!("Other error: {}", e),
    }
    Ok(())
}

§Examples

Basic usage:

use rust_ethernet_ip::{EipClient, PlcValue};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let mut client = EipClient::connect("192.168.1.100:44818").await?;

    // Read a boolean tag
    let motor_running = client.read_tag("MotorRunning").await?;

    // Write an integer tag
    client.write_tag("SetPoint", PlcValue::Dint(1500)).await?;

    // Read multiple tags in sequence
    let tag1 = client.read_tag("Tag1").await?;
    let tag2 = client.read_tag("Tag2").await?;
    let tag3 = client.read_tag("Tag3").await?;
    Ok(())
}

Advanced usage with error recovery:

use rust_ethernet_ip::{EipClient, PlcValue, EtherNetIpError};
use tokio::time::Duration;

async fn read_with_retry(client: &mut EipClient, tag: &str, retries: u32) -> Result<PlcValue, EtherNetIpError> {
    for attempt in 0..retries {
        match client.read_tag(tag).await {
            Ok(value) => return Ok(value),
            Err(EtherNetIpError::Connection(_)) => {
                if attempt < retries - 1 {
                    tokio::time::sleep(Duration::from_secs(1)).await;
                    continue;
                }
                return Err(EtherNetIpError::Protocol("Max retries exceeded".to_string()));
            }
            Err(e) => return Err(e),
        }
    }
    Err(EtherNetIpError::Protocol("Max retries exceeded".to_string()))
}

Implementations§

Source§

impl EipClient

Source

pub async fn new(addr: &str) -> Result<Self>

Source

pub async fn connect(addr: &str) -> Result<Self>

Public async connect function for EipClient

Source

pub fn set_max_packet_size(&mut self, size: u32)

Sets the maximum packet size for communication

Source

pub async fn discover_tags(&mut self) -> Result<()>

Discovers all tags in the PLC (including hierarchical UDT members)

Source

pub async fn discover_udt_members( &mut self, udt_name: &str, ) -> Result<Vec<(String, TagMetadata)>>

Discovers UDT members for a specific structure

Source

pub async fn get_udt_definition_cached( &self, udt_name: &str, ) -> Option<UdtDefinition>

Gets cached UDT definition

Source

pub async fn list_udt_definitions(&self) -> Vec<String>

Lists all cached UDT definitions

Source

pub async fn discover_tags_detailed(&mut self) -> Result<Vec<TagAttributes>>

Discovers all tags with full attributes This method queries the PLC for all available tags and their detailed attributes

Source

pub async fn discover_program_tags( &mut self, program_name: &str, ) -> Result<Vec<TagAttributes>>

Discovers program-scoped tags This method discovers tags within a specific program scope

Source

pub async fn list_cached_tag_attributes(&self) -> Vec<String>

Lists all cached tag attributes

Source

pub async fn clear_caches(&mut self)

Clears all caches (UDT definitions, templates, tag attributes)

Source

pub async fn with_route_path(addr: &str, route: RoutePath) -> Result<Self>

Creates a new client with a specific route path

Source

pub async fn connect_with_stream<S>( stream: S, route: Option<RoutePath>, ) -> Result<Self>
where S: EtherNetIpStream + 'static,

Connect to a PLC using a custom stream

This method allows you to provide your own stream implementation, enabling:

  • Wrapping streams for metrics/observability (bytes in/out)
  • Applying custom socket options (keepalive, timeouts, bind local address)
  • Reusing pre-established tunnels/connections
  • Using in-memory streams for deterministic testing
§Arguments
  • stream - Any stream that implements AsyncRead + AsyncWrite + Unpin + Send
§Example
use rust_ethernet_ip::EipClient;
use std::net::SocketAddr;
use tokio::net::TcpStream;

// Create a custom stream with socket options
let addr: SocketAddr = "192.168.1.100:44818".parse()?;
let stream = TcpStream::connect(addr).await?;
stream.set_nodelay(true)?;

// Connect using the custom stream
let client = EipClient::connect_with_stream(stream, None).await?;
Source

pub fn set_route_path(&mut self, route: RoutePath)

Sets the route path for the client

Source

pub fn get_route_path(&self) -> Option<&RoutePath>

Gets the current route path

Source

pub fn clear_route_path(&mut self)

Removes the route path (uses direct connection)

Source

pub async fn get_tag_metadata(&self, tag_name: &str) -> Option<TagMetadata>

Gets metadata for a tag

Source

pub async fn read_tag(&mut self, tag_name: &str) -> Result<PlcValue>

Reads a tag value from the PLC

This function performs a CIP read request for the specified tag. The tag’s data type is automatically determined from the PLC’s response.

v0.6.0: For UDT tags, this returns PlcValue::Udt(UdtData) with symbol_id and raw bytes. Use UdtData::parse() with a UDT definition to access members.

§Arguments
  • tag_name - The name of the tag to read
§Returns

The tag’s value as a PlcValue enum. For UDTs, this is PlcValue::Udt(UdtData).

§Examples
use rust_ethernet_ip::{EipClient, PlcValue};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let mut client = EipClient::connect("192.168.1.100:44818").await?;

    // Read different data types
    let bool_val = client.read_tag("MotorRunning").await?;
    let int_val = client.read_tag("Counter").await?;
    let real_val = client.read_tag("Temperature").await?;

    // Read a UDT (v0.6.0: returns UdtData)
    let udt_val = client.read_tag("MyUDT").await?;
    if let PlcValue::Udt(udt_data) = udt_val {
        let udt_def = client.get_udt_definition("MyUDT").await?;
        // Convert UdtDefinition to UserDefinedType
        let mut user_def = rust_ethernet_ip::udt::UserDefinedType::new(udt_def.name.clone());
        for member in &udt_def.members {
            user_def.add_member(member.clone());
        }
        let members = udt_data.parse(&user_def)?;
        println!("UDT has {} members", members.len());
    }

    // Handle the result
    match bool_val {
        PlcValue::Bool(true) => println!("Motor is running"),
        PlcValue::Bool(false) => println!("Motor is stopped"),
        _ => println!("Unexpected data type"),
    }
    Ok(())
}
§Performance
  • Latency: 1-5ms typical
  • Throughput: 1,500+ ops/sec
  • Network: 1 request/response cycle
§Error Handling

Common errors:

  • Protocol: Tag doesn’t exist or invalid format
  • Connection: Lost connection to PLC
  • Timeout: Operation timed out
Source

pub fn build_write_array_request_with_index( &self, base_array_name: &str, start_index: u32, element_count: u16, data_type: u16, data: &[u8], ) -> Result<Vec<u8>>

Builds a CIP Write Tag Service request for array elements with element addressing

This method uses proper CIP element addressing (0x28/0x29/0x2A segments) in the Request Path to write to specific array elements or ranges.

Reference: 1756-PM020, Pages 603-611, 855-867 (Writing to Array Element)

§Arguments
  • base_array_name - Base name of the array (e.g., “MyArray” for “MyArray[10]”)
  • start_index - Starting element index (0-based)
  • element_count - Number of elements to write
  • data_type - CIP data type code (e.g., 0x00C4 for DINT)
  • data - Raw bytes of the data to write
§Example

Writing value 0x12345678 to element 10 of array “MyArray”:

let data = 0x12345678u32.to_le_bytes();
let request = client.build_write_array_request_with_index(
    "MyArray", 10, 1, 0x00C4, &data
)?;
Source

pub async fn read_udt_chunked(&mut self, tag_name: &str) -> Result<PlcValue>

Reads a UDT with advanced chunked reading to handle large structures

v0.6.0: Returns PlcValue::Udt(UdtData) with symbol_id and raw bytes. Use UdtData::parse() with a UDT definition to access individual members.

This method uses multiple strategies to handle large UDTs that exceed the maximum packet size, including intelligent chunking and member discovery.

§Arguments
  • tag_name - The name of the UDT tag to read
§Returns

PlcValue::Udt(UdtData) containing the symbol_id and raw data bytes

§Example
let udt_value = client.read_udt_chunked("Part_Data").await?;
if let rust_ethernet_ip::PlcValue::Udt(udt_data) = udt_value {
    println!("UDT symbol_id: {}, data size: {} bytes", udt_data.symbol_id, udt_data.data.len());
    // Parse members if needed
    let udt_def = client.get_udt_definition("Part_Data").await?;
    // Convert UdtDefinition to UserDefinedType
    let mut user_def = rust_ethernet_ip::udt::UserDefinedType::new(udt_def.name.clone());
    for member in &udt_def.members {
        user_def.add_member(member.clone());
    }
    let members = udt_data.parse(&user_def)?;
}
Source

pub async fn read_udt_member_by_offset( &mut self, udt_name: &str, member_offset: usize, member_size: usize, data_type: u16, ) -> Result<PlcValue>

Reads a specific UDT member by offset

This method reads a specific member of a UDT by calculating its offset and reading only that portion of the UDT.

§Arguments
  • udt_name - The name of the UDT tag
  • member_offset - The byte offset of the member in the UDT
  • member_size - The size of the member in bytes
  • data_type - The data type of the member (0x00C1 for BOOL, 0x00CA for REAL, etc.)
§Example
let member_value = client.read_udt_member_by_offset("MyUDT", 0, 1, 0x00C1).await?;
println!("Member value: {:?}", member_value);
Source

pub async fn write_udt_member_by_offset( &mut self, udt_name: &str, member_offset: usize, member_size: usize, data_type: u16, value: PlcValue, ) -> Result<()>

Writes a specific UDT member by offset

This method writes a specific member of a UDT by calculating its offset and writing only that portion of the UDT.

§Arguments
  • udt_name - The name of the UDT tag
  • member_offset - The byte offset of the member in the UDT
  • member_size - The size of the member in bytes
  • data_type - The data type of the member (0x00C1 for BOOL, 0x00CA for REAL, etc.)
  • value - The value to write
§Example
client.write_udt_member_by_offset("MyUDT", 0, 1, 0x00C1, PlcValue::Bool(true)).await?;
Source

pub async fn get_udt_definition( &mut self, udt_name: &str, ) -> Result<UdtDefinition>

Gets UDT definition from the PLC This method queries the PLC for the UDT structure and caches it for future use

Source

pub async fn get_tag_attributes( &mut self, tag_name: &str, ) -> Result<TagAttributes>

Gets tag attributes from the PLC

Source

pub async fn write_tag(&mut self, tag_name: &str, value: PlcValue) -> Result<()>

Writes a value to a PLC tag

This method automatically determines the best communication method based on the data type:

  • STRING values use unconnected explicit messaging with proper AB STRING format
  • Other data types use standard unconnected messaging

v0.6.0: For UDT tags, pass PlcValue::Udt(UdtData). The symbol_id must be set (typically obtained by reading the UDT first). If symbol_id is 0, the method will attempt to read tag attributes to get the symbol_id automatically.

§Arguments
  • tag_name - The name of the tag to write to
  • value - The value to write. For UDTs, use PlcValue::Udt(UdtData).
§Example
use rust_ethernet_ip::{PlcValue, UdtData};

// Write simple types
client.write_tag("Counter", PlcValue::Dint(42)).await?;
client.write_tag("Message", PlcValue::String("Hello PLC".to_string())).await?;

// Write UDT (v0.6.0: read first to get symbol_id, then modify and write)
let udt_value = client.read_tag("MyUDT").await?;
if let PlcValue::Udt(mut udt_data) = udt_value {
    let udt_def = client.get_udt_definition("MyUDT").await?;
    // Convert UdtDefinition to UserDefinedType
    let mut user_def = rust_ethernet_ip::udt::UserDefinedType::new(udt_def.name.clone());
    for member in &udt_def.members {
        user_def.add_member(member.clone());
    }
    let mut members = udt_data.parse(&user_def)?;
    members.insert("Member1".to_string(), PlcValue::Dint(100));
    let modified_udt = UdtData::from_hash_map(&members, &user_def, udt_data.symbol_id)?;
    client.write_tag("MyUDT", PlcValue::Udt(modified_udt)).await?;
}
Source

pub fn build_list_tags_request(&self) -> Vec<u8>

Source

pub async fn check_health(&self) -> bool

Checks the health of the connection

Source

pub async fn check_health_detailed(&mut self) -> Result<bool>

Performs a more thorough health check by actually communicating with the PLC

Source

pub async fn send_cip_request(&self, cip_request: &[u8]) -> Result<Vec<u8>>

Sends a CIP request wrapped in EtherNet/IP SendRRData command

Source

pub async fn unregister_session(&mut self) -> Result<()>

Unregisters the EtherNet/IP session with the PLC

Source

pub fn build_element_id_segment(&self, index: u32) -> Vec<u8>

Builds an Element ID segment for array element addressing

Reference: 1756-PM020, Pages 603-611, 870-890 (Element ID Segment Size Selection)

Element ID segments use different sizes based on index value:

  • 0-255: 8-bit Element ID (0x28 + 1 byte value)
  • 256-65535: 16-bit Element ID (0x29 0x00 + 2 bytes low, high)
  • 65536+: 32-bit Element ID (0x2A 0x00 + 4 bytes lowest to highest)
Source

pub fn build_base_tag_path(&self, tag_name: &str) -> Vec<u8>

Builds base tag path without array element addressing

Extracts the base tag name from array notation (e.g., “MyArray[5]” -> “MyArray”) Reference: 1756-PM020, Page 894-909 (ANSI Extended Symbol Segment Construction)

Source

pub fn build_read_array_request( &self, base_array_name: &str, start_index: u32, element_count: u16, ) -> Vec<u8>

Builds a CIP Read Tag Service request for array elements with element addressing

This method uses proper CIP element addressing (0x28/0x29/0x2A segments) in the Request Path to read specific array elements or ranges.

Reference: 1756-PM020, Pages 603-611, 815-851 (Array Element Addressing Examples)

§Arguments
  • base_array_name - Base name of the array (e.g., “MyArray” for “MyArray[10]”)
  • start_index - Starting element index (0-based)
  • element_count - Number of elements to read
§Example

Reading elements 10-14 of array “MyArray” (5 elements):

let request = client.build_read_array_request("MyArray", 10, 5);

This generates:

  • Request Path: [0x91] “MyArray” [0x28] [0x0A] (element 10)
  • Request Data: [0x05 0x00] (5 elements)
Source

pub async fn execute_batch( &mut self, operations: &[BatchOperation], ) -> Result<Vec<BatchResult>>

Executes a batch of read and write operations

This is the main entry point for batch operations. It takes a slice of BatchOperation items and executes them efficiently by grouping them into optimal CIP packets based on the current BatchConfig.

§Arguments
  • operations - A slice of operations to execute
§Returns

A vector of BatchResult items, one for each input operation. Results are returned in the same order as the input operations.

§Performance
  • Throughput: 5,000-15,000+ operations/second (vs 1,500 individual)
  • Latency: 5-20ms per batch (vs 1-3ms per individual operation)
  • Network efficiency: 1-5 packets vs N packets for N operations
§Examples
use rust_ethernet_ip::{EipClient, BatchOperation, PlcValue};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let mut client = EipClient::connect("192.168.1.100:44818").await?;

    let operations = vec![
        BatchOperation::Read { tag_name: "Motor1_Speed".to_string() },
        BatchOperation::Read { tag_name: "Motor2_Speed".to_string() },
        BatchOperation::Write {
            tag_name: "SetPoint".to_string(),
            value: PlcValue::Dint(1500)
        },
    ];

    let results = client.execute_batch(&operations).await?;

    for result in results {
        match result.result {
            Ok(Some(value)) => println!("Read value: {:?}", value),
            Ok(None) => println!("Write successful"),
            Err(e) => println!("Operation failed: {}", e),
        }
    }

    Ok(())
}
Source

pub async fn read_tags_batch( &mut self, tag_names: &[&str], ) -> Result<Vec<(String, Result<PlcValue, BatchError>)>>

Reads multiple tags in a single batch operation

This is a convenience method for read-only batch operations. It’s optimized for reading many tags at once.

§Arguments
  • tag_names - A slice of tag names to read
§Returns

A vector of tuples containing (tag_name, result) pairs

§Examples
use rust_ethernet_ip::EipClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let mut client = EipClient::connect("192.168.1.100:44818").await?;

    let tags = ["Motor1_Speed", "Motor2_Speed", "Temperature", "Pressure"];
    let results = client.read_tags_batch(&tags).await?;

    for (tag_name, result) in results {
        match result {
            Ok(value) => println!("{}: {:?}", tag_name, value),
            Err(e) => println!("{}: Error - {}", tag_name, e),
        }
    }

    Ok(())
}
Source

pub async fn write_tags_batch( &mut self, tag_values: &[(&str, PlcValue)], ) -> Result<Vec<(String, Result<(), BatchError>)>>

Writes multiple tag values in a single batch operation

This is a convenience method for write-only batch operations. It’s optimized for writing many values at once.

§Arguments
  • tag_values - A slice of (tag_name, value) tuples to write
§Returns

A vector of tuples containing (tag_name, result) pairs

§Examples
use rust_ethernet_ip::{EipClient, PlcValue};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let mut client = EipClient::connect("192.168.1.100:44818").await?;

    let writes = vec![
        ("SetPoint1", PlcValue::Bool(true)),
        ("SetPoint2", PlcValue::Dint(2000)),
        ("EnableFlag", PlcValue::Bool(true)),
    ];

    let results = client.write_tags_batch(&writes).await?;

    for (tag_name, result) in results {
        match result {
            Ok(_) => println!("{}: Write successful", tag_name),
            Err(e) => println!("{}: Write failed - {}", tag_name, e),
        }
    }

    Ok(())
}
Source

pub fn configure_batch_operations(&mut self, config: BatchConfig)

Configures batch operation settings

This method allows fine-tuning of batch operation behavior, including performance optimizations and error handling.

§Arguments
  • config - The new batch configuration to use
§Examples
use rust_ethernet_ip::{EipClient, BatchConfig};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let mut client = EipClient::connect("192.168.1.100:44818").await?;

    let config = BatchConfig {
        max_operations_per_packet: 50,
        max_packet_size: 1500,
        packet_timeout_ms: 5000,
        continue_on_error: false,
        optimize_packet_packing: true,
    };

    client.configure_batch_operations(config);

    Ok(())
}
Source

pub fn get_batch_config(&self) -> &BatchConfig

Gets current batch operation configuration

Source

pub async fn write_ab_string_components( &mut self, tag_name: &str, value: &str, ) -> Result<()>

Writes a string value using Allen-Bradley UDT component access This writes to TestString.LEN and TestString.DATA separately

Source

pub async fn write_ab_string_udt( &mut self, tag_name: &str, value: &str, ) -> Result<()>

Writes a string using a single UDT write with proper AB STRING format

Source

pub async fn write_string_connected( &mut self, tag_name: &str, value: &str, ) -> Result<()>

Writes a string using connected explicit messaging

Source

pub async fn write_string_unconnected( &mut self, tag_name: &str, value: &str, ) -> Result<()>

Writes a string using unconnected explicit messaging with proper AB STRING format

This method uses standard unconnected messaging instead of connected messaging and implements the proper Allen-Bradley STRING structure as described in the provided information about Len, MaxLen, and Data[82] format.

Source

pub async fn write_string(&mut self, tag_name: &str, value: &str) -> Result<()>

Write a string value to a PLC tag using unconnected messaging

§Arguments
  • tag_name - The name of the tag to write to
  • value - The string value to write (max 82 characters)
§Returns
  • Ok(()) if the write was successful
  • Err(EtherNetIpError) if the write failed
§Errors
  • StringTooLong - If the string is longer than 82 characters
  • InvalidString - If the string contains invalid characters
  • TagNotFound - If the tag doesn’t exist
  • WriteError - If the write operation fails
Source

pub async fn subscribe_to_tag( &self, tag_path: &str, options: SubscriptionOptions, ) -> Result<()>

Subscribes to a tag for real-time updates

Source

pub async fn subscribe_to_tags( &self, tags: &[(&str, SubscriptionOptions)], ) -> Result<()>

Trait Implementations§

Source§

impl Clone for EipClient

Source§

fn clone(&self) -> EipClient

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for EipClient

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more