Files
StandardSence/StandardScene.Protocol.VDA5050/VDACar/MasterMQTTCommunication.cs
T
2026-06-14 11:19:15 +08:00

297 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CommonUsage.Protocols.VDA5050.Messages;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Extensions.ManagedClient;
using MQTTnet.Protocol;
using MQTTnet.Server;
using Newtonsoft.Json;
using SimpleCore;
using SimpleCore.Library;
namespace StandardScene.CarTypes
{
public class MasterMQTTCommunication
{
private IManagedMqttClient _client;
private IManagedMqttClient _visualizationClient; // Separate client for visualization
private const string OrderTopic = "vda5050/frldAGV/order";
private const string StateTopic = "vda5050/frldAGV/state";
private const string VisualizationTopic = "vda5050/frldAGV/visualization";
private readonly string _connectionTopic = "vda5050/frldAGV/connection";
private readonly string _instantAction = "vda5050/frldAGV/instantActions";
private readonly string _factsheet = "vda5050/frldAGV/factsheet";
private readonly string _carFields = "vda5050/frldAGV/carFields";
//192.168.123.5
public MasterMQTTCommunication()
{
// Initialize MQTT client and connect to broker
var mqttFactory = new MqttFactory();
_client = mqttFactory.CreateManagedMqttClient();
var mqttClientOptions = new MqttClientOptionsBuilder()
.WithTcpServer("localhost", 1883) // Connect to the local broker
.WithCleanSession(true)
.WithCleanStart(true)
.Build();
var managedOptions = new ManagedMqttClientOptionsBuilder()
.WithClientOptions(mqttClientOptions)
.WithMaxPendingMessages(20)
.WithPendingMessagesOverflowStrategy(MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage)
.Build();
_client.StartAsync(managedOptions).GetAwaiter().GetResult();
Console.WriteLine(" >>> Master-Control MQTT client connected to broker.");
// Initialize separate client for visualization
_visualizationClient = mqttFactory.CreateManagedMqttClient();
var visualizationOptions = new MqttClientOptionsBuilder()
.WithTcpServer("localhost", 1883)
.WithClientId("Master-Visualization")
.Build();
var visualizationManagedOptions = new ManagedMqttClientOptionsBuilder()
.WithClientOptions(visualizationOptions)
.WithMaxPendingMessages(10) // Lower queue size for visualization
.WithPendingMessagesOverflowStrategy(MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage)
.Build();
_visualizationClient.StartAsync(visualizationManagedOptions).GetAwaiter().GetResult();
Console.WriteLine(" >>> Master-Control Visualization MQTT client initialized.");
}
public async Task RestartClient()
{
Console.WriteLine(" >>> Restarting MQTT client...");
var stopTask = _client.StopAsync();
if (await Task.WhenAny(stopTask, Task.Delay(5000)) == stopTask)
{
Console.WriteLine(" >>> MQTT client stopped successfully.");
}
else
{
Console.WriteLine(" >>> Timeout while stopping MQTT client.");
}
// Dispose and reinitialize the client
//_client.Dispose();
var mqttFactory = new MqttFactory();
var newClient = mqttFactory.CreateManagedMqttClient();
var mqttClientOptions = new MqttClientOptionsBuilder()
.WithTcpServer("localhost", 1883)
.Build();
var managedOptions = new ManagedMqttClientOptionsBuilder()
.WithClientOptions(mqttClientOptions)
.Build();
await newClient.StartAsync(managedOptions);
Console.WriteLine(" >>> New MQTT client started.");
}
public void SubsribeToConnectionTopic()
{
_client.SubscribeAsync(_connectionTopic, MqttQualityOfServiceLevel.AtLeastOnce).GetAwaiter().GetResult();
_client.ApplicationMessageReceivedAsync += async e =>
{
if (e.ApplicationMessage.Topic == _connectionTopic)
{
Console.WriteLine($" >>>>>>> Subscribed to topic: {e.ApplicationMessage.Topic}");
var payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
//LogMessage("RECEIVED", e.ApplicationMessage.Topic, payload);
var connectionStatusMessage = JsonConvert.DeserializeObject<connectionMessage>(payload);
var car = (VDA5050Car)SimpleLib.GetAllCars()
.FirstOrDefault(cc => cc is VDA5050Car vdaCar);
if (car == null)
{
Diagnosis.Post($"no car of serialNumber {connectionStatusMessage.serialNumber}");
}
car.ConnectionStatus = connectionStatusMessage.connectionState;
Console.WriteLine($">>>> Connection status: {connectionStatusMessage.connectionState}");
}
};
}
public void SubscribeToCarFields()
{
_client.SubscribeAsync(_carFields,MqttQualityOfServiceLevel.AtLeastOnce).GetAwaiter().GetResult();
_client.ApplicationMessageReceivedAsync += async e =>
{
if (e.ApplicationMessage.Topic == _carFields)
{
var payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
Console.WriteLine(payload);
//TODO:处理字符串,拿想要的值
}
};
}
//public void SubsribeToFactSheetTopic()
//{
// _client.SubscribeAsync(_factsheet, MqttQualityOfServiceLevel.AtMostOnce).GetAwaiter().GetResult();
// _client.ApplicationMessageReceivedAsync += async e =>
// {
// if (e.ApplicationMessage.Topic == _factsheet)
// {
// //Console.WriteLine($" >>>>>>> Subscribed to topic: {e.ApplicationMessage.Topic}");
// var payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
// //LogMessage("RECEIVED FactSheet", e.ApplicationMessage.Topic, payload);
// // Console.WriteLine($">>>> Connection status: {connectionStatusMessage.connectionState}");
// }
// };
//}
public void SubscribeToVisualization()
{
_visualizationClient.SubscribeAsync(VisualizationTopic, MqttQualityOfServiceLevel.AtMostOnce).GetAwaiter().GetResult();
Console.WriteLine($" >>> Subscribed to {VisualizationTopic}");
_visualizationClient.ApplicationMessageReceivedAsync += async e =>
{
if(_visualizationClient.PendingApplicationMessagesCount > 5)
{
Console.WriteLine($"[WARNING] Dropping old visualization message. Pending: {_visualizationClient.PendingApplicationMessagesCount}");
return; // Skip processing to catch up
}
if (e.ApplicationMessage.Topic == VisualizationTopic)
{
var payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
//Console.WriteLine($"[DEBUG] Received Visualization Message: {payload}");
var state = JsonConvert.DeserializeObject<visualizationMessage>(payload);
var car = (VDA5050Car)SimpleLib.GetAllCars()
.FirstOrDefault(cc => cc is VDA5050Car vdaCar);
if (car != null)
{
car.UpdatePosition(state);
}
}
await Task.CompletedTask;
};
}
public void SubscribeToState()
{
_client.SubscribeAsync(StateTopic, MqttQualityOfServiceLevel.AtMostOnce).GetAwaiter().GetResult();
Console.WriteLine($"Subscribed to topic: {StateTopic}");
_client.ApplicationMessageReceivedAsync += async e =>
{
Console.WriteLine("e.ApplicationMessage.Topic: " + e.ApplicationMessage.Topic + " StateTopic: " + StateTopic);
if (e.ApplicationMessage.Topic == StateTopic)
{
Console.WriteLine($" >>>>>>> Subscribed to topic: {e.ApplicationMessage.Topic}");
var payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
//LogMessage("RECEIVED", e.ApplicationMessage.Topic, payload);
// Console.WriteLine($" >> Topic: [{e.ApplicationMessage.Topic}] -- {payload}");
var state = JsonConvert.DeserializeObject<stateMessage>(payload);
var car = (VDA5050Car)SimpleLib.GetAllCars()
.FirstOrDefault(cc => cc is VDA5050Car vdaCar);
if (car == null)
{
Diagnosis.Post($"no car of serialNumber {state.serialNumber}");
}
car.IsPaused = state.paused;
car.UpdateState(state);
//car.UpdatePosition(state);
//Console.WriteLine($">> Received message on topic '{StateTopic}': {payload}");
// onTopicReceived(state);
}
await Task.CompletedTask;
};
}
//public void SubscribeToState()
//{
// _client.SubscribeAsync(StateTopic, MqttQualityOfServiceLevel.AtMostOnce).GetAwaiter().GetResult();
// _client.ApplicationMessageReceivedAsync += async e =>
// {
// if (e.ApplicationMessage.Topic == StateTopic)
// {
// var payload = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
// var state = JsonConvert.DeserializeObject<stateMessage>(payload);
// var car = (VDA5050Car)SimpleLib.GetAllCars().FirstOrDefault(cc => cc is VDA5050Car);
// if (car == null)
// {
// Diagnosis.Post($"no car of serialNumber {state.serialNumber}");
// }
// else
// {
// // Instead of calling UpdateState/UpdatePosition directly,
// // simply store the latest state message.
// car.SetLatestState(state);
// }
// }
// await Task.CompletedTask;
// };
//}
public async Task PublishTo(string order)
{
var message = new MqttApplicationMessageBuilder()
.WithTopic(OrderTopic)
.WithPayload(order)
.WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtMostOnce)
.Build();
//Console.WriteLine($"[MQTT-Master] Pending Messages before sending: {_client.PendingApplicationMessagesCount}");
await _client.EnqueueAsync(message);
//Console.WriteLine($"[MQTT-Master] Sent order message. Pending Messages after sending: {_client.PendingApplicationMessagesCount}");
//LogMessage("Sent Order", OrderTopic, order);
}
public async Task PublishInstantActions(string actions)
{
var message = new MqttApplicationMessageBuilder()
.WithTopic(_instantAction)
.WithPayload(actions)
.Build();
await _client.EnqueueAsync(message);
}
public void LogMessage(string direction, string topic, string payload)
{
string formattedPayload = payload;
// Try to parse the payload as JSON and pretty-print it
try
{
var jsonObject = JsonConvert.DeserializeObject(payload);
formattedPayload = JsonConvert.SerializeObject(jsonObject, Formatting.Indented);
}
catch (JsonReaderException)
{
// If the payload is not valid JSON, just leave it as is
formattedPayload = payload;
}
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] [{direction}] Topic: {topic}, Payload: {formattedPayload}");
}
}
}