@using MudBlazor
@using Microsoft.AspNetCore.SignalR.Client
@using RobotNet10.RobotApp.Client.Clients
@using RobotNet10.RobotApp.Client.Shared.Devices
@implements IAsyncDisposable
@inject ModbusTcpHubClient ModbusTcpHubClient
@inject ISnackbar Snackbar
@DeviceName
@DeviceId
IP: @ModbusData.IpAddress
Port: @ModbusData.Port
Slave ID: @ModbusData.SlaveId
@(ModbusData.IsConnected ? "Connected" : "Disconnected")
@if (ModbusData.HoldingRegisters != null && ModbusData.HoldingRegisters.Length > 0)
{
@foreach (var range in ModbusData.HoldingRegisters)
{
Holding Registers: @range.Name
Address: @range.StartAddress - @(range.StartAddress + range.Quantity - 1) (@range.Quantity registers)
Address
Index
Name
Value (Decimal)
Value (Hex)
@context.Address
@context.Index
@if (!string.IsNullOrEmpty(context.Name))
{
@context.Name
}
else
{
-
}
@context.Value
0x@(context.Value.ToString("X4"))
}
}
@if (ModbusData.InputRegisters != null && ModbusData.InputRegisters.Length > 0)
{
@foreach (var range in ModbusData.InputRegisters)
{
Input Registers: @range.Name
Address: @range.StartAddress - @(range.StartAddress + range.Quantity - 1) (@range.Quantity registers)
Address
Index
Name
Value (Decimal)
Value (Hex)
@context.Address
@context.Index
@if (!string.IsNullOrEmpty(context.Name))
{
@context.Name
}
else
{
-
}
@context.Value
0x@(context.Value.ToString("X4"))
}
}
@if (ModbusData.Coils != null && ModbusData.Coils.Length > 0)
{
@foreach (var range in ModbusData.Coils)
{
Coils: @range.Name
Address: @range.StartAddress - @(range.StartAddress + range.Quantity - 1) (@range.Quantity coils)
Address
Index
Name
Value
Action
@context.Address
@context.Index
@if (!string.IsNullOrEmpty(context.Name))
{
@context.Name
}
else
{
-
}
@(context.Value ? "ON" : "OFF")
@{
var coilKey = $"{range.StartAddress}_{context.Index}";
var isWriting = WritingCoils.ContainsKey(coilKey) && WritingCoils[coilKey];
}
@if (isWriting)
{
}
}
}
@if (ModbusData.DiscreteInputs != null && ModbusData.DiscreteInputs.Length > 0)
{
@foreach (var range in ModbusData.DiscreteInputs)
{
Discrete Inputs: @range.Name
Address: @range.StartAddress - @(range.StartAddress + range.Quantity - 1) (@range.Quantity inputs)
Address
Index
Name
Value
@context.Address
@context.Index
@if (!string.IsNullOrEmpty(context.Name))
{
@context.Name
}
else
{
-
}
@(context.Value ? "ON" : "OFF")
}
}
@code {
[Parameter, EditorRequired]
public string DeviceId { get; set; } = string.Empty;
private string DeviceName { get; set; } = string.Empty;
private ModbusTcpData ModbusData = new();
private bool IsLoading => !ModbusTcpHubClient.IsConnected;
private bool IsReloading = false;
private Dictionary WritingCoils = new();
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && !string.IsNullOrEmpty(DeviceId))
{
await ConnectAsync();
}
await base.OnAfterRenderAsync(firstRender);
}
private async Task ConnectAsync()
{
try
{
await ModbusTcpHubClient.StartAsync();
// Lấy DeviceName từ ModbusTcpHub
var deviceInfo = await ModbusTcpHubClient.GetDeviceInfoAsync(DeviceId);
if (deviceInfo != null)
{
DeviceName = deviceInfo.DeviceName;
}
else
{
DeviceName = DeviceId; // Fallback to DeviceId if not found
}
ModbusData = await ModbusTcpHubClient.GetModbusDataAsync(DeviceId);
StateHasChanged();
}
catch (Exception ex)
{
Snackbar.Add($"Failed to connect: {ex.Message}", Severity.Error);
}
}
private async Task DisconnectAsync()
{
try
{
await ModbusTcpHubClient.StopAsync();
ModbusData = new ModbusTcpData(); // Reset về giá trị mặc định
StateHasChanged();
}
catch (Exception ex)
{
Snackbar.Add($"Failed to disconnect: {ex.Message}", Severity.Error);
}
}
private async Task ReloadModbusDataAsync()
{
if (!ModbusTcpHubClient.IsConnected || IsReloading)
return;
try
{
IsReloading = true;
StateHasChanged();
ModbusData = await ModbusTcpHubClient.GetModbusDataAsync(DeviceId);
}
catch (Exception ex)
{
Snackbar.Add($"Failed to reload Modbus data: {ex.Message}", Severity.Error);
}
finally
{
IsReloading = false;
StateHasChanged();
}
}
private async Task HandleCoilToggle(ushort address, bool value, string coilKey)
{
if (!ModbusTcpHubClient.IsConnected)
{
Snackbar.Add("Not connected to Modbus device", Severity.Warning);
return;
}
// Set writing state
WritingCoils[coilKey] = true;
StateHasChanged();
try
{
var success = await ModbusTcpHubClient.WriteCoilAsync(DeviceId, address, value);
if (success)
{
Snackbar.Add($"Coil {address} set to {(value ? "ON" : "OFF")}", Severity.Success);
// Reload data để cập nhật giá trị mới nhất
await ReloadModbusDataAsync();
}
else
{
Snackbar.Add($"Failed to write coil {address}", Severity.Error);
// Reload để khôi phục giá trị cũ
await ReloadModbusDataAsync();
}
}
catch (Exception ex)
{
Snackbar.Add($"Error writing coil {address}: {ex.Message}", Severity.Error);
// Reload để khôi phục giá trị cũ
await ReloadModbusDataAsync();
}
finally
{
WritingCoils[coilKey] = false;
StateHasChanged();
}
}
public async ValueTask DisposeAsync()
{
await DisconnectAsync();
}
}