This commit is contained in:
Đăng Nguyễn 2025-12-22 21:28:57 +07:00
parent 30732b4b9f
commit e4e135e35f
6 changed files with 75 additions and 45 deletions

View File

@ -77,6 +77,13 @@
</div> </div>
</div> </div>
<script>
window.ScrollToBottom = (element) => {
if (element) {
element.scrollTop = element.scrollHeight;
}
};
</script>
@code { @code {
private DateTime DateLog = DateTime.Today; private DateTime DateLog = DateTime.Today;

View File

@ -23,7 +23,7 @@
.log-level { .log-level {
display: inline-block; display: inline-block;
width: 46px; width: 60px;
} }
.log-head { .log-head {

View File

@ -560,10 +560,14 @@ public partial class RobotConfigManager
private async Task LoadConfig() private async Task LoadConfig()
{ {
IsLoading = true;
StateHasChanged();
var response = await (await Http.PostAsync($"api/RobotConfigs/load", null)).Content.ReadFromJsonAsync<MessageResult>(); var response = await (await Http.PostAsync($"api/RobotConfigs/load", null)).Content.ReadFromJsonAsync<MessageResult>();
if (response is null) Snackbar.Add("Failed to load config", Severity.Warning); if (response is null) Snackbar.Add("Failed to load config", Severity.Warning);
else if (!response.IsSuccess) Snackbar.Add(response.Message ?? "Failed to load config", Severity.Warning); else if (!response.IsSuccess) Snackbar.Add(response.Message ?? "Failed to load config", Severity.Warning);
else Snackbar.Add("Config loaded", Severity.Success); else Snackbar.Add("Config loaded", Severity.Success);
IsLoading = false;
StateHasChanged(); StateHasChanged();
} }
} }

View File

@ -147,11 +147,11 @@ public class MQTTClient : IAsyncDisposable
MqttClient = MqttClientFactory.CreateMqttClient(); MqttClient = MqttClientFactory.CreateMqttClient();
//MqttClient.ApplicationMessageReceivedAsync -= OnMessageReceived; MqttClient.ApplicationMessageReceivedAsync -= OnMessageReceived;
MqttClient.ApplicationMessageReceivedAsync += OnMessageReceived; MqttClient.ApplicationMessageReceivedAsync += OnMessageReceived;
//MqttClient.DisconnectedAsync -= OnDisconnected; MqttClient.DisconnectedAsync -= OnDisconnected;
MqttClient.DisconnectedAsync += OnDisconnected; MqttClient.DisconnectedAsync += OnDisconnected;
while (!cancellationToken.IsCancellationRequested) while (!cancellationToken.IsCancellationRequested && !IsDisposed)
{ {
try try
{ {
@ -168,7 +168,11 @@ public class MQTTClient : IAsyncDisposable
{ {
Logger.Error($"Lỗi khi tạo MQTT client: {ex.Message}"); Logger.Error($"Lỗi khi tạo MQTT client: {ex.Message}");
} }
await Task.Delay(3000, cancellationToken); try
{
await Task.Delay(3000, cancellationToken);
}
catch { }
} }
} }
else throw new ObjectDisposedException(nameof(MQTTClient)); else throw new ObjectDisposedException(nameof(MQTTClient));
@ -219,10 +223,10 @@ public class MQTTClient : IAsyncDisposable
var tlsOptions = new MqttClientTlsOptionsBuilder() var tlsOptions = new MqttClientTlsOptionsBuilder()
.UseTls(true) .UseTls(true)
.WithSslProtocols(System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls13) .WithSslProtocols(System.Security.Authentication.SslProtocols.Tls12 | System.Security.Authentication.SslProtocols.Tls13)
//.WithCertificateValidationHandler(ValidateCertificates) .WithCertificateValidationHandler(ValidateCertificates)
.WithClientCertificatesProvider(new MQTTClientCertificatesProvider(VDA5050Setting.CerFile, VDA5050Setting.KeyFile)) .WithClientCertificatesProvider(new MQTTClientCertificatesProvider(VDA5050Setting.CerFile, VDA5050Setting.KeyFile))
.Build(); .Build();
builder = builder.WithTlsOptions(tlsOptions); builder = builder.WithTlsOptions(tlsOptions);
} }
MqttClientOptions = builder.Build(); MqttClientOptions = builder.Build();
} }
@ -251,42 +255,42 @@ public class MQTTClient : IAsyncDisposable
{ {
//if (!IsDisposed) //if (!IsDisposed)
//{ //{
if (MqttClient is null) throw new Exception("Kết nối tới broker chưa được khởi tạo nhưng đã yêu cầu subscribe"); if (MqttClient is null) throw new Exception("Kết nối tới broker chưa được khởi tạo nhưng đã yêu cầu subscribe");
if (!MqttClient.IsConnected) throw new Exception("Kết nối tới broker chưa thành công nhưng đã yêu cầu subscribe"); if (!MqttClient.IsConnected) throw new Exception("Kết nối tới broker chưa thành công nhưng đã yêu cầu subscribe");
while (!cancellationToken.IsCancellationRequested) while (!cancellationToken.IsCancellationRequested)
{
try
{ {
try var response = await MqttClient.SubscribeAsync(MqttClientSubscribeOptions, cancellationToken);
bool isSuccess = true;
foreach (var item in response.Items)
{ {
var response = await MqttClient.SubscribeAsync(MqttClientSubscribeOptions, cancellationToken); if (item.ResultCode == MqttClientSubscribeResultCode.GrantedQoS0 ||
bool isSuccess = true; item.ResultCode == MqttClientSubscribeResultCode.GrantedQoS1 ||
foreach (var item in response.Items) item.ResultCode == MqttClientSubscribeResultCode.GrantedQoS2)
{ {
if (item.ResultCode == MqttClientSubscribeResultCode.GrantedQoS0 || Logger.Info($"Subscribe thành công cho topic: {item.TopicFilter.Topic} với QoS: {item.ResultCode}");
item.ResultCode == MqttClientSubscribeResultCode.GrantedQoS1 || }
item.ResultCode == MqttClientSubscribeResultCode.GrantedQoS2) else
{ {
Logger.Info($"Subscribe thành công cho topic: {item.TopicFilter.Topic} với QoS: {item.ResultCode}"); Logger.Warning($"Subscribe thất bại cho topic: {item.TopicFilter.Topic}. Lý do: {response.ReasonString}");
} isSuccess = false;
else break;
{
Logger.Warning($"Subscribe thất bại cho topic: {item.TopicFilter.Topic}. Lý do: {response.ReasonString}");
isSuccess = false;
break;
}
} }
if (isSuccess) break;
}
catch (Exception ex)
{
Logger.Error($"Lỗi khi subscribe: {ex.Message}");
}
if (!cancellationToken.IsCancellationRequested && !IsDisposed)
{
await Task.Delay(3000, cancellationToken);
} }
if (isSuccess) break;
} }
catch (Exception ex)
{
Logger.Error($"Lỗi khi subscribe: {ex.Message}");
}
if (!cancellationToken.IsCancellationRequested && !IsDisposed)
{
await Task.Delay(3000, cancellationToken);
}
}
//} //}
//else throw new ObjectDisposedException(nameof(MQTTClient)); //else throw new ObjectDisposedException(nameof(MQTTClient));
} }

View File

@ -57,8 +57,8 @@ public class RobotConfiguration(IServiceProvider ServiceProvider, Logger<RobotCo
if (IsReady) if (IsReady)
{ {
var robotConnection = scope.ServiceProvider.GetRequiredService<RobotConnection>(); var robotConnection = scope.ServiceProvider.GetRequiredService<RobotConnection>();
await robotConnection.StopConnection();
robotConnection.StartConnection(); robotConnection.StartConnection();
await Task.Delay(1000);
} }
} }
else throw new Exception("Chưa có cấu hình VDA5050."); else throw new Exception("Chưa có cấu hình VDA5050.");

View File

@ -3,6 +3,7 @@ using RobotApp.VDA5050;
using RobotApp.VDA5050.InstantAction; using RobotApp.VDA5050.InstantAction;
using RobotApp.VDA5050.Order; using RobotApp.VDA5050.Order;
using System.Text.Json; using System.Text.Json;
using System.Threading;
namespace RobotApp.Services.Robot; namespace RobotApp.Services.Robot;
@ -10,12 +11,13 @@ public class RobotConnection(RobotConfiguration RobotConfiguration,
Logger<RobotConnection> Logger, Logger<RobotConnection> Logger,
Logger<MQTTClient> MQTTClientLogger) Logger<MQTTClient> MQTTClientLogger)
{ {
private readonly VDA5050Setting VDA5050Setting = RobotConfiguration.VDA5050Setting;
private MQTTClient? MqttClient; private MQTTClient? MqttClient;
public bool IsConnected => MqttClient is not null && MqttClient.IsConnected; public bool IsConnected => MqttClient is not null && MqttClient.IsConnected;
public event Action<OrderMsg>? OrderUpdated; public event Action<OrderMsg>? OrderUpdated;
public event Action<InstantActionsMsg>? ActionUpdated; public event Action<InstantActionsMsg>? ActionUpdated;
private readonly SemaphoreSlim _connectionSemaphore = new(1, 1);
private CancellationTokenSource? _connectionCancel;
private void OrderChanged(string data) private void OrderChanged(string data)
@ -50,7 +52,7 @@ public class RobotConnection(RobotConfiguration RobotConfiguration,
public async Task<MessageResult> Publish(string topic, string data) public async Task<MessageResult> Publish(string topic, string data)
{ {
if (MqttClient is not null && MqttClient.IsConnected) return await MqttClient.PublishAsync($"{VDA5050Setting.TopicPrefix}/{VDA5050Setting.Manufacturer}/{RobotConfiguration.SerialNumber}/{topic}", data); if (MqttClient is not null && MqttClient.IsConnected) return await MqttClient.PublishAsync($"{RobotConfiguration.VDA5050Setting.TopicPrefix}/{RobotConfiguration.VDA5050Setting.Manufacturer}/{RobotConfiguration.SerialNumber}/{topic}", data);
return new(false, "Chưa có kết nối tới broker"); return new(false, "Chưa có kết nối tới broker");
} }
public void StartConnection() public void StartConnection()
@ -58,16 +60,29 @@ public class RobotConnection(RobotConfiguration RobotConfiguration,
Task.Run(async () => Task.Run(async () =>
{ {
await StartConnectionAsync(CancellationToken.None); await StartConnectionAsync(CancellationToken.None);
Logger.Info("Robot đã kết nối tới Fleet Manager."); if(IsConnected)Logger.Info("Robot đã kết nối tới Fleet Manager.");
}); });
} }
public async Task StartConnectionAsync(CancellationToken cancellationToken) public async Task StartConnectionAsync(CancellationToken cancellationToken)
{ {
MqttClient = new MQTTClient(RobotConfiguration.SerialNumber, VDA5050Setting, MQTTClientLogger); try
MqttClient.OrderChanged += OrderChanged; {
MqttClient.InstanceActionsChanged += InstanceActionsChanged; await StopConnection();
await MqttClient.ConnectAsync(cancellationToken); _connectionCancel?.Cancel();
await MqttClient.SubscribeAsync(cancellationToken); if (_connectionSemaphore.Wait(1000, cancellationToken))
{
_connectionCancel = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
MqttClient = new MQTTClient(RobotConfiguration.SerialNumber, RobotConfiguration.VDA5050Setting, MQTTClientLogger);
MqttClient.OrderChanged += OrderChanged;
MqttClient.InstanceActionsChanged += InstanceActionsChanged;
await MqttClient.ConnectAsync(_connectionCancel.Token);
if(MqttClient is not null) await MqttClient.SubscribeAsync(_connectionCancel.Token);
}
}
finally
{
_connectionSemaphore.Release();
}
} }
public async Task StopConnection() public async Task StopConnection()