use std::time::Duration;
use voltage_modbus::{regs_to_f32, ByteOrder, ModbusClient, ModbusResult, ModbusTcpClient};
struct MeterConfig {
address: &'static str,
slave_id: u8,
byte_order: ByteOrder,
}
#[derive(Debug)]
struct MeterReading {
voltage: f32,
current: f32,
active_power: f32,
power_factor: f32,
frequency: f32,
total_energy: f32,
}
fn read_f32(registers: &[u16], byte_order: ByteOrder) -> f32 {
if registers.len() >= 2 {
regs_to_f32(&[registers[0], registers[1]], byte_order)
} else {
0.0
}
}
async fn read_meter_bulk(
client: &mut ModbusTcpClient,
config: &MeterConfig,
) -> ModbusResult<MeterReading> {
let registers = client.read_03(config.slave_id, 0x0000, 12).await?;
Ok(MeterReading {
voltage: read_f32(®isters[0..2], config.byte_order),
current: read_f32(®isters[2..4], config.byte_order),
active_power: read_f32(®isters[4..6], config.byte_order),
power_factor: read_f32(®isters[6..8], config.byte_order),
frequency: read_f32(®isters[8..10], config.byte_order),
total_energy: read_f32(®isters[10..12], config.byte_order),
})
}
async fn read_meter_individual(
client: &mut ModbusTcpClient,
config: &MeterConfig,
) -> ModbusResult<MeterReading> {
let regs = client.read_03(config.slave_id, 0x0000, 2).await?;
let voltage = read_f32(®s, config.byte_order);
let regs = client.read_03(config.slave_id, 0x0002, 2).await?;
let current = read_f32(®s, config.byte_order);
let regs = client.read_03(config.slave_id, 0x0004, 2).await?;
let active_power = read_f32(®s, config.byte_order);
let regs = client.read_03(config.slave_id, 0x0006, 2).await?;
let power_factor = read_f32(®s, config.byte_order);
let regs = client.read_03(config.slave_id, 0x0008, 2).await?;
let frequency = read_f32(®s, config.byte_order);
let regs = client.read_03(config.slave_id, 0x000A, 2).await?;
let total_energy = read_f32(®s, config.byte_order);
Ok(MeterReading {
voltage,
current,
active_power,
power_factor,
frequency,
total_energy,
})
}
fn display_reading(reading: &MeterReading) {
println!("┌────────────────────────────────────┐");
println!("│ Power Meter Reading │");
println!("├────────────────────────────────────┤");
println!("│ Voltage: {:>10.2} V │", reading.voltage);
println!("│ Current: {:>10.3} A │", reading.current);
println!("│ Active Power: {:>10.1} W │", reading.active_power);
println!("│ Power Factor: {:>10.3} │", reading.power_factor);
println!("│ Frequency: {:>10.2} Hz │", reading.frequency);
println!("│ Total Energy: {:>10.2} kWh │", reading.total_energy);
println!("└────────────────────────────────────┘");
}
#[tokio::main]
async fn main() -> ModbusResult<()> {
let config = MeterConfig {
address: "127.0.0.1:502", slave_id: 1,
byte_order: ByteOrder::BigEndian, };
println!("Connecting to meter at {}...", config.address);
let mut client = ModbusTcpClient::from_address(config.address, Duration::from_secs(5)).await?;
println!("Connected!\n");
println!("=== Bulk Read (Optimized) ===\n");
let reading = read_meter_bulk(&mut client, &config).await?;
display_reading(&reading);
println!("\n=== Individual Reads (Demonstration) ===\n");
let reading = read_meter_individual(&mut client, &config).await?;
display_reading(&reading);
let stats = client.get_stats();
println!(
"\nCommunication stats: {} requests, {} responses",
stats.requests_sent, stats.responses_received
);
client.close().await?;
Ok(())
}