From a552e1262f543d3d4eb6f89b7c4f09520c1191ac Mon Sep 17 00:00:00 2001 From: Karatekuh Date: Sat, 23 Mar 2024 13:47:04 +0100 Subject: [PATCH] Updated MPS to switch between mqtt and opcua, and added a mqtt test and also a broker to the test suite --- .github/workflows/dotnet.yml | 6 +++ Simulator/Configurations.cs | 40 ++++++++++++-- Simulator/MPS/MQTThelper.cs | 3 +- Simulator/MPS/Mps.cs | 87 ++++++++++++++++++------------ Simulator/MPS/MpsManager.cs | 2 +- Simulator/cfg/config.yaml | 6 ++- Simulatortests/BaseStationTests.cs | 34 ++++++++++-- Simulatortests/MQTTTestHelper.cs | 75 ++++++++++++++++++++++++++ 8 files changed, 208 insertions(+), 45 deletions(-) create mode 100644 Simulatortests/MQTTTestHelper.cs diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 57d283e..f7d35a8 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -23,5 +23,11 @@ jobs: run: dotnet restore - name: Build run: dotnet build --no-restore + - name: Start Mosquitto + uses: namoshek/mosquitto-github-action@v1 + with: + version: '1.6' + ports: '1883:1883' + container-name: 'mosquitto' - name: Test run: dotnet test Simulatortests/Simulatortests.csproj --no-build --verbosity normal \ No newline at end of file diff --git a/Simulator/Configurations.cs b/Simulator/Configurations.cs index e08de32..0fd3afe 100644 --- a/Simulator/Configurations.cs +++ b/Simulator/Configurations.cs @@ -50,7 +50,6 @@ public class Configurations public uint WebguiPort { get; private set;} public bool BarcodeScanner { get; private set; } - public Configurations() { MpsConfigs = new List(); @@ -357,8 +356,10 @@ public void LoadConfig(string path) private static RefboxConfig? CreateRefboxConfig(YamlMappingNode refbox) { string? ip = null; - int publicSendPort = 0, publicRecvPort = 0, cyanSendPort = 0, cyanRecvPort = 0, magentaSendPort = 0, magentaRecvPort = 0, tcpPort = 0; + int publicSendPort = 0, publicRecvPort = 0, cyanSendPort = 0, cyanRecvPort = 0, magentaSendPort = 0, magentaRecvPort = 0, tcpPort = 0, broker_port = 1883; var children = refbox.Children; + var broker_ip = ""; + var mqtt_active = false; // Step into the public information //Console.WriteLine(children[0].Key.ToString()); var map = (YamlMappingNode)children[0].Value; @@ -427,9 +428,31 @@ public void LoadConfig(string path) } } break; + case "mqtt": + var mqttChild = ((YamlMappingNode)value).Children; + foreach (var (yamlNode, yamlNode1) in mqttChild) + { + switch (yamlNode.ToString().ToLower()) + { + case "broker_ip": + broker_ip = yamlNode1.ToString().ToLower(); + break; + case "broker_port": + broker_port = int.Parse(yamlNode1.ToString()); + break; + case "active": + mqtt_active = bool.Parse(yamlNode1.ToString()); + break; + default: + Console.WriteLine("Unknown key " + yamlNode.ToString()); + return null; + } + } + break; default: Console.WriteLine("Unknown key " + key.ToString()); return null; + } //Console.WriteLine(val); @@ -439,7 +462,7 @@ public void LoadConfig(string path) return null; } var config = new RefboxConfig(ip, tcpPort, publicSendPort, publicRecvPort, cyanSendPort, cyanRecvPort, - magentaSendPort, magentaRecvPort); + magentaSendPort, magentaRecvPort,broker_ip,broker_port ,mqtt_active); return config; } @@ -537,8 +560,11 @@ public class RefboxConfig public int CyanRecvPort { get; } public int MagentaSendPort { get; } public int MagentaRecvPort { get; } + public string BrokerIp { get; } + public int BrokerPort { get; } + public bool MqttMode { get; } - public RefboxConfig(string ip,int tcpPort, int publicSend, int publicRecv, int cyanSend, int cyanRecv, int magentaSend, int magentaRecv) + public RefboxConfig(string ip,int tcpPort, int publicSend, int publicRecv, int cyanSend, int cyanRecv, int magentaSend, int magentaRecv, string broker_ip = "localhost", int brokerPort = 1883, bool active = false) { IP = ip; TcpPort = tcpPort; @@ -548,6 +574,9 @@ public RefboxConfig(string ip,int tcpPort, int publicSend, int publicRecv, int c CyanSendPort = cyanSend; MagentaRecvPort = magentaRecv; MagentaSendPort = magentaSend; + BrokerIp = broker_ip; + BrokerPort = brokerPort; + MqttMode = active; } public void PrintConfig() { @@ -560,6 +589,9 @@ public void PrintConfig() Console.WriteLine("CyanSendPort = [" + CyanSendPort + "]"); Console.WriteLine("MagentaRecvPort = [" + MagentaRecvPort + "]"); Console.WriteLine("MagentaSendPort = [" + MagentaSendPort + "]"); + Console.WriteLine("BrokerIp = [" + BrokerIp + "]"); + Console.WriteLine("BrokerPort = [" + BrokerPort + "]"); + Console.WriteLine("MqttMode = [" + MqttMode + "]"); } } diff --git a/Simulator/MPS/MQTThelper.cs b/Simulator/MPS/MQTThelper.cs index 2013eed..9c59624 100644 --- a/Simulator/MPS/MQTThelper.cs +++ b/Simulator/MPS/MQTThelper.cs @@ -40,7 +40,7 @@ public enum bits private ManualResetEvent BasicEvent; private MyLogger _myLogger; - public MQTThelper(string name, string url, ManualResetEvent inevent, ManualResetEvent basicevent, MyLogger logger) + public MQTThelper(string name, string url, int port, ManualResetEvent inevent, ManualResetEvent basicevent, MyLogger logger) { Name = name; _myLogger = logger; @@ -58,6 +58,7 @@ public void Connect() _myLogger.Log("Starting connection!"); var mqttClientOptions = new MqttClientOptionsBuilder() .WithTcpServer(Url) + .WithClientId(Name) .WithWillQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce) .Build(); Client.ConnectAsync(mqttClientOptions, CancellationToken.None).GetAwaiter().GetResult(); diff --git a/Simulator/MPS/Mps.cs b/Simulator/MPS/Mps.cs index 9a35d3b..1cdd24f 100644 --- a/Simulator/MPS/Mps.cs +++ b/Simulator/MPS/Mps.cs @@ -42,7 +42,7 @@ public abstract class Mps public uint SlideCount { get; set; } public string JsonInformation; protected Configurations Config; - protected MQTThelper MqttHelper; + public MQTThelper MqttHelper; protected bool MQTT; public bool Working { get; private set; } public enum MpsType @@ -90,16 +90,16 @@ protected Mps(Configurations config, string name, int port, int id, Team team, b GreenLight = new Light(LightColor.Green, LightEvent); TaskDescription = "idle"; Config = config; - MQTT = true; + MQTT = Config.Refbox != null; // Belt = new Belt(this, BeltEvent); // Checking whether we have mockup mode or normal mode /*if (Configurations.GetInstance().MockUp) return;*/ try { - if (MQTT) + if (Config.Refbox != null && Config.Refbox.MqttMode) { - MqttHelper= new MQTThelper(Name, "mosquitto", InEvent, BasicEvent, MyLogger); + MqttHelper= new MQTThelper(Name, config.Refbox.BrokerIp,config.Refbox.BrokerPort, InEvent, BasicEvent, MyLogger); MqttHelper.Connect(); MqttHelper.Setup(); } @@ -128,38 +128,58 @@ public void Run() public void ResetMachine() { TaskDescription = "Reseting!"; - MqttHelper.InNodes.Status.SetBusy(true); - //InNodes.StatusNodes.busy.Value = true; - //Refbox.ApplyChanges(InNodes.StatusNodes.busy); - MqttHelper.InNodes.Status.SetEnable(false); - //InNodes.StatusNodes.enable.Value = false; - //Refbox.ApplyChanges(InNodes.StatusNodes.enable); + if(MQTT) + { + MqttHelper.InNodes.Status.SetBusy(true); + MqttHelper.InNodes.Status.SetEnable(false); + } + else + { + InNodes.StatusNodes.busy.Value = true; + Refbox.ApplyChanges(InNodes.StatusNodes.busy); + InNodes.StatusNodes.enable.Value = false; + Refbox.ApplyChanges(InNodes.StatusNodes.enable); + } Thread.Sleep(1000); - MqttHelper.InNodes.SetActionId(0); - //InNodes.ActionId.Value = 0; - ////Refbox.ApplyChanges(InNodes.ActionId); - MqttHelper.InNodes.SetData0(0); - //InNodes.Data0.Value = 0; - ////Refbox.ApplyChanges(InNodes.Data0); - MqttHelper.InNodes.SetData1(0); - //InNodes.Data1.Value = 0; - ////Refbox.ApplyChanges(InNodes.Data1); - MqttHelper.InNodes.SetError(0); - //InNodes.ByteError.Value = 0; - ////Refbox.ApplyChanges(InNodes.ByteError); - MqttHelper.InNodes.Status.SetReady(false); - //InNodes.StatusNodes.ready.Value = false; - ////Refbox.ApplyChanges(InNodes.StatusNodes.ready); - MqttHelper.InNodes.Status.SetError(false); - //InNodes.StatusNodes.error.Value = false; - ////Refbox.ApplyChanges(InNodes.StatusNodes.error); + if(MQTT) + { + MqttHelper.InNodes.SetActionId(0); + MqttHelper.InNodes.SetData0(0); + MqttHelper.InNodes.SetData1(0); + MqttHelper.InNodes.SetError(0); + MqttHelper.InNodes.Status.SetReady(false); + MqttHelper.InNodes.Status.SetError(false); + } + else + { + InNodes.ActionId.Value = 0; + Refbox.ApplyChanges(InNodes.ActionId); + InNodes.Data0.Value = 0; + Refbox.ApplyChanges(InNodes.Data0); + InNodes.Data1.Value = 0; + Refbox.ApplyChanges(InNodes.Data1); + InNodes.ByteError.Value = 0; + Refbox.ApplyChanges(InNodes.ByteError); + InNodes.StatusNodes.ready.Value = false; + Refbox.ApplyChanges(InNodes.StatusNodes.ready); + InNodes.StatusNodes.error.Value = false; + Refbox.ApplyChanges(InNodes.StatusNodes.error); + } + + ProductAtIn = null; ProductAtOut = null; ProductOnBelt = null; - - MqttHelper.InNodes.Status.SetBusy(false); - //InNodes.StatusNodes.busy.Value = false; - //Refbox.ApplyChanges(InNodes.StatusNodes.busy); + if(MQTT) + { + MqttHelper.InNodes.Status.SetBusy(false); + } + else + { + InNodes.StatusNodes.busy.Value = false; + Refbox.ApplyChanges(InNodes.StatusNodes.busy); + } + TaskDescription = "Idle"; } @@ -545,7 +565,8 @@ public void SerializeMachineToJson() public void StopMachine() { - Refbox.Stop(); + if (Refbox != null) + Refbox.Stop(); } } } \ No newline at end of file diff --git a/Simulator/MPS/MpsManager.cs b/Simulator/MPS/MpsManager.cs index ff059d1..228c6c6 100644 --- a/Simulator/MPS/MpsManager.cs +++ b/Simulator/MPS/MpsManager.cs @@ -1,4 +1,4 @@ -using Simulator.Utility; + using Simulator.Utility; using System; using System.Collections.Generic; using System.Linq; diff --git a/Simulator/cfg/config.yaml b/Simulator/cfg/config.yaml index 63562a3..47ad434 100644 --- a/Simulator/cfg/config.yaml +++ b/Simulator/cfg/config.yaml @@ -144,7 +144,7 @@ teams: port: 2016 refbox: public: - ip: 127.0.0.1 + ip: 127.0.0.1 # is also used as mqtt broker address # THe simulation communicates via tcp to get ground-truth tcp: 4444 send: 4445 @@ -155,6 +155,10 @@ refbox: magenta: send: 4442 recv: 4447 + mqtt: + broker_ip: localhost + broker_port: 1883 + active: true webui: prefix: http port: 8000 diff --git a/Simulatortests/BaseStationTests.cs b/Simulatortests/BaseStationTests.cs index eaa6b99..35888fe 100644 --- a/Simulatortests/BaseStationTests.cs +++ b/Simulatortests/BaseStationTests.cs @@ -1,10 +1,9 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Simulator.MPS; -using LlsfMsgs; -using System.Threading; +using LlsfMsgs; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Simulator; -using Opc.UaFx.Client; +using Simulator.MPS; using Simulator.Utility; +using System.Threading; namespace Simulatortests { @@ -63,6 +62,31 @@ public void OPC_DispenseBase() testHelper.CloseConnection(); machine.StopMachine(); } + + [TestMethod] + public void MQTT_DispenseBase() + { + var ip = "mosquitto"; + var port = 1883; + var name = "C-BS"; + var config = new Configurations(); + config.Refbox = new RefboxConfig(ip:"127.0.0.1",0,0,0,0,0,0,0, ip, port, true); + var machine = new MPS_BS(config, name, port, 0, Team.Cyan, true); + var thread = new Thread(machine.Run); + thread.Start(); + Thread.Sleep(500); + Assert.AreEqual(machine.MqttHelper.InNodes.ActionId, 0); + var testHelper = new MQTTTestHelper(ip, port, name); + if (!testHelper.CreateConnection()) + Assert.Fail(); + testHelper.SendTask((ushort)MPS_BS.BaseSpecificActions.GetBase, (ushort)1, (ushort)0); + Thread.Sleep(config.BSTaskDuration + 300); + Assert.IsNotNull(machine.ProductOnBelt); + testHelper.CloseConnection(); + machine.StopMachine(); + } + + [TestMethod] public void OPC_WrongDispenseBase() { diff --git a/Simulatortests/MQTTTestHelper.cs b/Simulatortests/MQTTTestHelper.cs new file mode 100644 index 0000000..864f9e9 --- /dev/null +++ b/Simulatortests/MQTTTestHelper.cs @@ -0,0 +1,75 @@ +using System; +using System.Threading; +using Google.Protobuf; +using MQTTnet; +using MQTTnet.Client; +using MQTTnet.Protocol; +using Org.BouncyCastle.Asn1; +using Simulator.MPS; + +namespace Simulatortests; + +public class MQTTTestHelper +{ + private string Name; + private string BasicTopic; + private string InTopic; + private string Url; + private IMqttClient Client; + private MqttFactory MqttFactory; + public static readonly string In = "In"; + public static readonly string Basic = "Basic"; + + public MQTTTestHelper(string ip, int port, string name) + { + Name = name; + BasicTopic = $"MPS/{Name}/{Basic}/"; + InTopic = $"MPS/{Name}/{In}/"; + Url = ip; + MqttFactory = new MqttFactory(); + Client = MqttFactory.CreateMqttClient(); + } + + public bool CreateConnection() + { + var mqttClientOptions = new MqttClientOptionsBuilder() + .WithTcpServer(Url) + .WithClientId("MQTTTestHelper") + .WithWillQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce) + .Build(); + Client.ConnectAsync(mqttClientOptions, CancellationToken.None).GetAwaiter().GetResult(); + return true; + } + + public void SendTask(ushort TaskId, ushort data0 = 0, ushort data1 = 0) + { + PublishChange(InTopic + "ActionId", TaskId); + PublishChange(InTopic + "Data/Data[0]", data0); + PublishChange(InTopic + "Data/Data[1]", data1); + PublishChange(InTopic + "Status/Enable", true); + } + public void PublishChange(string topic, int value) + { + Console.Write("Topic: " + topic); + var applicationMessage = new MqttApplicationMessageBuilder() + .WithTopic(topic) + .WithPayload(value.ToString()) + .Build(); + Client.PublishAsync(applicationMessage, CancellationToken.None).GetAwaiter(); + } + + public void PublishChange(string topic, bool value) + { + Console.Write("Topic: " + topic); + var applicationMessage = new MqttApplicationMessageBuilder() + .WithTopic(topic) + .WithPayload(value.ToString()) + .Build(); + Client.PublishAsync(applicationMessage, CancellationToken.None).GetAwaiter(); + } + + public void CloseConnection() + { + Client.DisconnectAsync(); + } +} \ No newline at end of file