diff --git a/Client.Utils/Constants.cs b/Client.Utils/Constants.cs index 8ffefd44..bf0862c0 100644 --- a/Client.Utils/Constants.cs +++ b/Client.Utils/Constants.cs @@ -20,7 +20,11 @@ namespace Client.Utils public static String CEF_LOCALES_PATH = BASE_PATH + "CEF\\Resources\\locales"; public static String CEF_EXCEPTIONLOG_PATH = BASE_PATH + "ExceptionLog"; public static String errorPageFile = BASE_PATH + "error.pg"; +<<<<<<< HEAD public static String JOB_OPENING_PATH = "C:\\CMS\\ACTIVE\\TMP\\clientTmpJob\\"; +======= + public static String JOB_OPENING_PATH = "C:\\CMS\\Active\\TMP\\clientTmpJob\\"; +>>>>>>> feature/Scada //Config Names public const string CONFIG_KEY = "Config"; diff --git a/Step.Config/Config/serverConfig.xml b/Step.Config/Config/serverConfig.xml index 5e174ed6..aef05b1c 100644 --- a/Step.Config/Config/serverConfig.xml +++ b/Step.Config/Config/serverConfig.xml @@ -1,8 +1,8 @@ - SIEMENS - false + DEMO + true localhost 8080 Ares 37 OF diff --git a/Step.Config/ServerConfig.cs b/Step.Config/ServerConfig.cs index 6154fe7e..1a2e5c27 100644 --- a/Step.Config/ServerConfig.cs +++ b/Step.Config/ServerConfig.cs @@ -1,6 +1,7 @@ using Step.Model.ConfigModels; using Step.Model.DatabaseModels; using Step.Model.DTOModels; +using Step.Model.DTOModels.Scada; using System.Collections.Generic; namespace Step.Config @@ -30,6 +31,12 @@ namespace Step.Config public static AreasConfigModel ScadaConfig; public static AreasConfigModel JobEditorConfig; + + public static List ProductionScadaSchema = new List(); + public static List ConfiguredScadaSchema = new List(); + + public static List SubscribedScada = new List(); + public static List MacrosConfig; } } \ No newline at end of file diff --git a/Step.Config/ServerConfigController.cs b/Step.Config/ServerConfigController.cs index f1ffb3e8..1604d244 100644 --- a/Step.Config/ServerConfigController.cs +++ b/Step.Config/ServerConfigController.cs @@ -1,6 +1,8 @@ using Step.Model.ConfigModels; +using Step.Model.DTOModels.Scada; using Step.Utils; using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; @@ -8,6 +10,7 @@ using System.Reflection; using System.Xml; using System.Xml.Linq; using System.Xml.Schema; +using System.Xml.Serialization; using static Step.Config.ServerConfig; using static Step.Model.Constants; using static Step.Utils.SupportFunctions; @@ -29,6 +32,7 @@ namespace Step.Config ReadHeadsConfig(); ReadToolManagerConfig(); ReadMacros(); + ReadScadaFile(); } catch (XmlException ex) { @@ -169,8 +173,41 @@ namespace Step.Config } } + private static void ReadScadaFile() + { + DirectoryInfo d = new DirectoryInfo(SCADA_DIRECTORY); + FileInfo[] files = d.GetFiles("*.xml"); + + int i = 1; + // Cycle inside xml files + foreach (var file in files) + { + StreamReader sr = new StreamReader(SCADA_DIRECTORY + file.Name); + XmlSerializer xmlSerializer = new XmlSerializer(typeof(ScadaSchemaModel)); + ScadaSchemaModel schema = xmlSerializer.Deserialize(sr) as ScadaSchemaModel; + schema.Id = i++; + // Setup incremental ids + schema.Layers = schema.Layers.Select(x => new ScadaSchemaLayerModel() + { + Id = i++, + Buttons = x.Buttons.Select(y => { y.Id = i++; return y; }).ToArray(), + Images = x.Images.Select(y => { y.Id = i++; return y; }).ToArray(), + ProgressBars = x.ProgressBars.Select(y => { y.Id = i++; return y; }).ToArray(), + Inputs = x.Inputs.Select(y => { y.Id = i++; return y; }).ToArray() + }) + .ToArray(); + + if (schema.IsInProductionPage == true) + ProductionScadaSchema.Add(schema); + else + ConfiguredScadaSchema.Add(schema); + } + } + + #region Read config from file from configuration + public static void ReadServerConfig() { // Get server file handler diff --git a/Step.Core/ThreadsFunctions.cs b/Step.Core/ThreadsFunctions.cs index 9d934a58..7758b334 100644 --- a/Step.Core/ThreadsFunctions.cs +++ b/Step.Core/ThreadsFunctions.cs @@ -3,14 +3,17 @@ using Step.Config; using Step.Core; using Step.Model.DTOModels; using Step.Model.DTOModels.AlarmModels; +using Step.Model.DTOModels.Scada; using Step.Model.DTOModels.ToolModels; using Step.NC; using Step.Utils; using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Threading; using TeamDev.SDK.MVVM; +using static Step.Config.ServerConfig; using static Step.Model.Constants; using static Step.Utils.ExceptionManager; @@ -29,7 +32,6 @@ public static class ThreadsFunctions private static long ReadToolDataTimer = 0, ReadToolDataTimes = 0; private static long WatchdogTimer = 0, WatchdogTimes = 0; - private static Thread ConnThread; #region Functions @@ -716,8 +718,8 @@ public static class ThreadsFunctions { ncHandler.Dispose(); } - } - + } + public static void MonitorPanelPCResources() { float sumRec, sumSen; @@ -726,7 +728,7 @@ public static class ThreadsFunctions int cardId = ServerConfig.ServerStartupConfig.NetworkCardId - 1; PerformanceCounterCategory performanceCounterCategory = new PerformanceCounterCategory("Network Interface"); - + if (cardId < 0 || cardId > performanceCounterCategory.GetInstanceNames().Length) { Monitor.Name = "No card to monitor"; @@ -734,9 +736,8 @@ public static class ThreadsFunctions return; } - Monitor.Name = performanceCounterCategory.GetInstanceNames()[cardId]; - - + Monitor.Name = performanceCounterCategory.GetInstanceNames()[cardId]; + PerformanceCounter PC_Bandwith = new PerformanceCounter("Network Interface", "Current Bandwidth", Monitor.Name); PerformanceCounter PC_RecievedBytes = new PerformanceCounter("Network Interface", "Bytes Received/sec", Monitor.Name); PerformanceCounter PC_SentBytes = new PerformanceCounter("Network Interface", "Bytes Sent/sec", Monitor.Name); @@ -756,7 +757,7 @@ public static class ThreadsFunctions sumRec += PC_RecievedBytes.NextValue(); sumSen += PC_SentBytes.NextValue(); } - Monitor.Value = Math.Round(((8 * (sumSen + sumRec)) / (Monitor.Bandwidth * 50) * 100), 2) ; + Monitor.Value = Math.Round(((8 * (sumSen + sumRec)) / (Monitor.Bandwidth * 50) * 100), 2); MessageServices.Current.Publish(NETWORK_USAGE, null, Monitor); sw.Stop(); @@ -767,13 +768,55 @@ public static class ThreadsFunctions catch (ThreadAbortException) { ExceptionManager.Manage(ERROR_LEVEL.FATAL, "Fatal error in Network Performance monitor Thread"); + } + } + + public static void ReadScadaData() + { + NcHandler ncHandler = new NcHandler(); + Stopwatch sw = new Stopwatch(); + + try + { + // Try connection + CmsError libraryError = ncHandler.Connect(); + if (libraryError.errorCode != 0) + ManageLibraryError(libraryError); + + while (true) + { + sw.Restart(); + + // Check if client is connected + if (ncHandler.numericalControl.NC_IsConnected()) + { + List scadaToRead = ProductionScadaSchema.Concat(SubscribedScada).ToList(); + + // Get new data from PLC + libraryError = ncHandler.ReadScadasData(scadaToRead, out List scadas); + if (libraryError.IsError()) + ManageLibraryError(libraryError); + + MessageServices.Current.Publish(SEND_SCADA_DATA, null, scadas); + } + else + RestoreConnection(); + sw.Stop(); + + // Wait + Thread.Sleep(CalcSleepTime(500, (int)sw.ElapsedMilliseconds)); + } } - } - + catch (ThreadAbortException) + { + ncHandler.Dispose(); + } + } + #endregion Functions - + #region SupportFunctions - + private static void TryNcConnection() { // Stop all the NC threads diff --git a/Step.Core/ThreadsHandler.cs b/Step.Core/ThreadsHandler.cs index e375c416..ac274f21 100644 --- a/Step.Core/ThreadsHandler.cs +++ b/Step.Core/ThreadsHandler.cs @@ -24,7 +24,8 @@ namespace Step.Core ThreadsFunctions.ReadActiveProgramData, ThreadsFunctions.UpdateToolsData, ThreadsFunctions.ReadNcMagazineActive, - ThreadsFunctions.ReadPartProgramQueueData + ThreadsFunctions.ReadPartProgramQueueData, + ThreadsFunctions.ReadScadaData // ThreadsFunctions.ReadNcSoftKeysData, }; diff --git a/Step.Database/DatabaseContext.cs b/Step.Database/DatabaseContext.cs index c973b87b..d7805609 100644 --- a/Step.Database/DatabaseContext.cs +++ b/Step.Database/DatabaseContext.cs @@ -175,7 +175,7 @@ namespace Step.Database // Get path to the HKEY_LOCAL_MACHINE/SOFTWARE RegistryKey key = Registry.LocalMachine.OpenSubKey("SOFTWARE", true); // Create or get ..//CMS/Step subkey - key = key.CreateSubKey("Cms").CreateSubKey("Step"); + key = key.CreateSubKey("Cms").CreateSubKey("Active"); // Set machine unique id Key key.SetValue(REGISTER_MACHINE_ID_KEY_NAME, uniqueId); } @@ -185,7 +185,7 @@ namespace Step.Database // Get path to the HKEY_LOCAL_MACHINE/SOFTWARE RegistryKey key = Registry.LocalMachine.OpenSubKey("SOFTWARE", true); // Get ..//CMS/Step subkey - key = key.CreateSubKey("Cms").CreateSubKey("Step"); + key = key.CreateSubKey("Cms").CreateSubKey("Active"); // Return value return (string)key.GetValue(REGISTER_MACHINE_ID_KEY_NAME); } diff --git a/Step.Model/Constants.cs b/Step.Model/Constants.cs index 89e1f2da..6e5c6e26 100644 --- a/Step.Model/Constants.cs +++ b/Step.Model/Constants.cs @@ -190,6 +190,7 @@ namespace Step.Model public const string SEND_QUEUE_DATA = "SEND_QUEUE_DATA"; public const string SEND_M155_DATA = "SEND_M155_DATA"; public const string NETWORK_USAGE = "NETWORK_USAGE"; + public const string SEND_SCADA_DATA = "SEND_SCADA_DATA"; public const string BROADCAST_DATA = "BROADCAST_DATA"; @@ -235,7 +236,9 @@ namespace Step.Model public const string TEMP_PP_FOLDER = TEMP_FOLDER + @"pp\"; public const string JOB_TMP_DIRECTORY = TEMP_PP_FOLDER + @"job\"; public const string QUEUE_TMP_FOLDER = TEMP_PP_FOLDER + @"queue\"; - public const string PART_PRG_IMAGES = TEMP_FOLDER + @"pp_img\"; + public const string PART_PRG_IMAGES = TEMP_FOLDER + @"pp_img\"; + + public const string SCADA_DIRECTORY = @"C:\CMS\Active\scada\"; public static readonly string[] VALID_FILE_EXTENSIONS = { "", ".txt", ".cnc", ".ini", ".mpf", ".spf" }; public static readonly string[] VALID_IMAGE_EXTENSIONS = { ".jpg", ".jpeg", ".png" }; diff --git a/Step.Model/DTOModels/Scada/DTOScadaModel.cs b/Step.Model/DTOModels/Scada/DTOScadaModel.cs new file mode 100644 index 00000000..5dfb6b5d --- /dev/null +++ b/Step.Model/DTOModels/Scada/DTOScadaModel.cs @@ -0,0 +1,183 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Step.Model.DTOModels.Scada +{ + public class DTOScadaModel + { + public int Id { get; set; } + public string Name { get; set; } + public bool IsInProductionPage { get; set; } + public List Buttons { get; set; } + public List Images { get; set; } + public List ProgressBars { get; set; } + public List Inputs { get; set; } + + public DTOScadaModel() + { + Name = ""; + Buttons = new List(); + Images = new List(); + ProgressBars = new List(); + Inputs = new List(); + } + + public override bool Equals(object obj) + { + var item = obj as DTOScadaModel; + if (item == null) + return false; + + if (item.Buttons.Count() != Buttons.Count() || item.Images.Count() != Images.Count() || item.ProgressBars.Count() != ProgressBars.Count() || item.Inputs.Count() != Inputs.Count()) + return false; + + // Compare lists of buttons, images, progressbar and inputs + bool listAreEquals = item.Buttons.All(Buttons.Contains); + if (!listAreEquals) + return false; + + listAreEquals = item.Images.All(Images.Contains); + if (!listAreEquals) + return false; + + listAreEquals = item.ProgressBars.All(ProgressBars.Contains); + if (!listAreEquals) + return false; + + listAreEquals = item.Inputs.All(Inputs.Contains); + if (!listAreEquals) + return false; + + return true; + } + } + + //public class DTOScadaLayerModel + //{ + // public int Id { get; set; } + // public List Buttons { get; set; } + // public List Images { get; set; } + // public List ProgressBars { get; set; } + // public List Inputs { get; set; } + + // public DTOScadaLayerModel() + // { + // Buttons = new List(); + // Images = new List(); + // ProgressBars = new List(); + // Inputs = new List(); + // } + //} + + public class DTOScadaButtonModel + { + public int Id { get; set; } + public bool Enabled { get; set; } + + public override bool Equals(object obj) + { + var item = obj as DTOScadaButtonModel; + if (item == null) + return false; + + if (item.Id != Id) + return false; + + if (item.Enabled != Enabled) + return false; + + return true; + } + } + + public class DTOScadaImageModel + { + public int Id { get; set; } + public bool IsVisible { get; set; } + + public override bool Equals(object obj) + { + var item = obj as DTOScadaImageModel; + if (item == null) + return false; + + + if (item.Id != Id) + return false; + + if (item.IsVisible != IsVisible) + return false; + + return true; + } + } + + public class DTOScadaProgressBarModel + { + public int Id { get; set; } + public byte Value { get; set; } + + public override bool Equals(object obj) + { + var item = obj as DTOScadaProgressBarModel; + if (item == null) + return false; + + if (item.Id != Id) + return false; + + if (item.Value != Value) + return false; + + return true; + } + } + + public class DTOScadaInputModel + { + public int Id { get; set; } + public DTOScadaValueModel Value { get; set; } + + public DTOScadaInputModel() + { + Id = 0; + Value = new DTOScadaValueModel(); + } + + public override bool Equals(object obj) + { + var item = obj as DTOScadaInputModel; + if (item == null) + return false; + + if (item.Id != Id) + return false; + + return item.Value.Equals(Value); + } + } + + public class DTOScadaValueModel + { + public bool IsVisible { get; set; } + public object Value { get; set; } + + public override bool Equals(object obj) + { + var item = obj as DTOScadaValueModel; + if (item == null) + return false; + + if (item.IsVisible != IsVisible) + return false; + + if(item.Value != null && item.Value != null) + { + if (!item.Value.Equals(Value)) + return false; + } + + return true; + } + } +} \ No newline at end of file diff --git a/Step.Model/DTOModels/Scada/ScadaSchemaModel.cs b/Step.Model/DTOModels/Scada/ScadaSchemaModel.cs new file mode 100644 index 00000000..5905ddfb --- /dev/null +++ b/Step.Model/DTOModels/Scada/ScadaSchemaModel.cs @@ -0,0 +1,212 @@ +using System.Collections.Generic; +using System.Xml.Serialization; + +namespace Step.Model.DTOModels.Scada +{ + [XmlRoot("scada")] + public class ScadaSchemaModel + { + public int Id { get; set; } + + [XmlElement("name")] + public string Name { get; set; } + [XmlElement("backgroundImagePath")] + public string BackgroundImage { get; set; } + [XmlElement("isInProductionPage")] + public bool IsInProductionPage { get; set; } + [XmlArray("layers")] + [XmlArrayItem("layer", typeof(ScadaSchemaLayerModel))] + public ScadaSchemaLayerModel[] Layers { get; set; } + } + + public class ScadaSchemaLayerModel + { + //[XmlElement("id")] + public int Id { get; set; } + + [XmlArray("buttons")] + [XmlArrayItem("button", typeof(ScadaSchemaButtonModel))] + public ScadaSchemaButtonModel[] Buttons { get; set; } + + [XmlArray("images")] + [XmlArrayItem("image", typeof(ScadaSchemaImageModel))] + public ScadaSchemaImageModel[] Images { get; set; } + + + [XmlArray("progressBars")] + [XmlArrayItem("progressBar", typeof(ScadaSchemaProgressBarModel))] + public ScadaSchemaProgressBarModel[] ProgressBars { get; set; } + + [XmlArray("inputs")] + [XmlArrayItem("input", typeof(ScadaSchemaInputModel))] + public ScadaSchemaInputModel[] Inputs { get; set; } + } + + public class ScadaSchemaButtonModel + { + //[XmlElement("id")] + public int Id { get; set; } + + [XmlElement("label")] + public ScadaSchemaLabelDataModel Label { get; set; } + + [XmlElement("position")] + public ScadaSchemaPositionModel Position { get; set; } + + [XmlElement("size")] + public ScadaSchemaSizeModel Size { get; set; } + + [XmlElement("status")] + public ScadaSchemaClickModel Status { get; set; } + } + + public class ScadaSchemaImageModel + { + //[XmlElement("id")] + public int Id { get; set; } + + [XmlElement("label")] + public ScadaSchemaLabelDataModel Label { get; set; } + + [XmlElement("position")] + public ScadaSchemaPositionModel Position { get; set; } + + [XmlElement("size")] + public ScadaSchemaSizeModel Size { get; set; } + + [XmlElement("status")] + public ScadaSchemaImgClickModel Status { get; set; } + } + + public class ScadaSchemaLabelModel + { + //[XmlElement("id")] + public int Id { get; set; } + + [XmlElement("label")] + public ScadaSchemaLabelDataModel Label { get; set; } + + [XmlElement("position")] + public ScadaSchemaPositionModel Position { get; set; } + + [XmlElement("size")] + public ScadaSchemaSizeModel Size { get; set; } + } + + public class ScadaSchemaProgressBarModel + { + //[XmlElement("id")] + public int Id { get; set; } + + [XmlElement("label")] + public ScadaSchemaLabelDataModel Label { get; set; } + + [XmlElement("position")] + public ScadaSchemaPositionModel Position { get; set; } + + [XmlElement("size")] + public ScadaSchemaSizeModel Size { get; set; } + + [XmlElement("memValueIndex")] + public string MemValueIndex { get; set; } + } + + public class ScadaSchemaInputModel + { + //[XmlElement("id")] + public int Id { get; set; } + + [XmlElement("label")] + public ScadaSchemaLabelDataModel Label { get; set; } + + [XmlElement("position")] + public ScadaSchemaPositionModel Position { get; set; } + + [XmlElement("size")] + public ScadaSchemaSizeModel Size { get; set; } + + [XmlElement("status")] + public ScadaSchemaInputDataModel Status { get; set; } + + } + + /// + /// Support objects + /// + public class ScadaSchemaLabelDataModel + { + [XmlElement("backgroundColor")] + public string BackgroundColor { get; set; } + + [XmlElement("textAlign")] + public string TextAlign { get; set; } + + [XmlElement("textColor")] + public string TextColor { get; set; } + + [XmlElement("textContent")] + public string TextContent { get; set; } + + [XmlElement("textSize")] + public int TextSize { get; set; } + } + + public class ScadaSchemaPositionModel + { + [XmlElement("x")] + public int X { get; set; } + [XmlElement("y")] + public int Y { get; set; } + } + + public class ScadaSchemaSizeModel + { + [XmlElement("x")] + public int X { get; set; } + [XmlElement("y")] + public int Y { get; set; } + } + + public class ScadaSchemaStatusModel + { + [XmlElement("memVisibleIndex")] + public string MemVisibleIndex { get; set; } + + [XmlElement("memValueIndex")] + public string MemValueIndex { get; set; } + + } + + public class ScadaSchemaClickModel + { + [XmlElement("memEnabledIndex")] + public string MemEnabledIndex { get; set; } + + [XmlElement("memClickIndex")] + public string MemClickIndex { get; set; } + } + + public class ScadaSchemaImgClickModel + { + [XmlElement("memVisibleIndex")] + public string MemVisibleIndex { get; set; } + + [XmlElement("memClickIndex")] + public string MemClickIndex { get; set; } + } + + public class ScadaSchemaInputDataModel + { + [XmlElement("memEnabledIndex")] + public string MemEnabledIndex { get; set; } + + [XmlElement("memValueIndex")] + public string MemValueIndex { get; set; } + + [XmlElement("type")] + public string Type { get; set; } + + [XmlElement("action")] + public string Action { get; set; } + } +} \ No newline at end of file diff --git a/Step.Model/Step.Model.csproj b/Step.Model/Step.Model.csproj index 0c398be5..3d048a37 100644 --- a/Step.Model/Step.Model.csproj +++ b/Step.Model/Step.Model.csproj @@ -110,6 +110,8 @@ + + diff --git a/Step.NC/NcHandler.cs b/Step.NC/NcHandler.cs index c5123ac6..553d9d28 100644 --- a/Step.NC/NcHandler.cs +++ b/Step.NC/NcHandler.cs @@ -10,6 +10,7 @@ using Step.Model.DTOModels; using Step.Model.DTOModels.AlarmModels; using Step.Model.DTOModels.JobModels; using Step.Model.DTOModels.MaintenanceModels; +using Step.Model.DTOModels.Scada; using Step.Model.DTOModels.ToolModels; using Step.Utils; using System; @@ -2372,5 +2373,185 @@ namespace Step.NC } #endregion Osai/Fanuc Tools + + public CmsError ReadScadasData(List schemasToRead, out List scadas) + { + CmsError cmsError = NO_ERROR; + scadas = new List(); + + List alreadyReadScada = new List(); + + foreach (var schema in schemasToRead) + { + // Avoid duplicated reads + if (!alreadyReadScada.Contains(schema.Id)) + { + // Read one schema + cmsError = ReadScadaData(schema, out DTOScadaModel scadaValue); + if (cmsError.IsError()) + return cmsError; + + // Add value to return list + scadas.Add(scadaValue); + // Add id to read scada + alreadyReadScada.Add(schema.Id); + } + } + + return cmsError; + } + + public CmsError ReadScadaData(ScadaSchemaModel scadaSchema, out DTOScadaModel scadaValue) + { + CmsError cmsError = NO_ERROR; + scadaValue = new DTOScadaModel() + { + Id = scadaSchema.Id, + Name = scadaSchema.Name, + IsInProductionPage = scadaSchema.IsInProductionPage, + Buttons = new List() + }; + + // Cycle inside layers + foreach (var layer in scadaSchema.Layers) + { + object val = null; + object val2 = null; + // Cycle through elements, use the max number of elements between layer components in order to be optimized + for (int i = 0; i < GetMaxCountBetweenLayerComponents(layer); i++) + { + if (layer.Buttons.ElementAt(i) != null) + { + // Read enabled from PLC + cmsError = numericalControl.PLC_RScadaValue(layer.Buttons[i].Status.MemEnabledIndex, SCADA_MEM_TYPE.BOOL, ref val); + if (cmsError.IsError()) + return cmsError; + // Populate & add new object into scada model + scadaValue.Buttons.Add(new DTOScadaButtonModel() + { + Id = layer.Buttons[i].Id, + Enabled = Convert.ToBoolean(val) + }); + } + + if (layer.Images.ElementAt(i) != null) + { + // Read isVisible from PLC + cmsError = numericalControl.PLC_RScadaValue(layer.Images[i].Status.MemVisibleIndex, SCADA_MEM_TYPE.BOOL, ref val); + if (cmsError.IsError()) + return cmsError; + // Populate & add new object into scada model + scadaValue.Images.Add(new DTOScadaImageModel() + { + Id = layer.Images[i].Id, + IsVisible = Convert.ToBoolean(val) + }); + } + + if (layer.ProgressBars.ElementAt(i) != null) + { + // Read value from PLC + cmsError = numericalControl.PLC_RScadaValue(layer.ProgressBars[i].MemValueIndex, SCADA_MEM_TYPE.BYTE, ref val); + if (cmsError.IsError()) + return cmsError; + // Populate & add new object into scada model + scadaValue.ProgressBars.Add(new DTOScadaProgressBarModel() + { + Id = layer.ProgressBars[i].Id, + Value = Convert.ToByte(val) + }); + } + + if (layer.Inputs.ElementAt(i) != null && layer.Inputs[i].Status.Action == "read") + { + // Read isVisible from PLC + cmsError = numericalControl.PLC_RScadaValue(layer.Inputs[i].Status.MemEnabledIndex, SCADA_MEM_TYPE.BOOL, ref val); + if (cmsError.IsError()) + return cmsError; + + // Read value from PLC + cmsError = numericalControl.PLC_RScadaValue(layer.Inputs[i].Status.MemValueIndex, GetMemTypeFromString(layer.Inputs[i].Status.Type), ref val2); + if (cmsError.IsError()) + return cmsError; + + // Populate & add new object into scada model + scadaValue.Inputs.Add(new DTOScadaInputModel() + { + Id = layer.Inputs[i].Id, + Value = new DTOScadaValueModel() + { + IsVisible = Convert.ToBoolean(val), + Value = val2 + } + }); + } + } + } + + return cmsError; + } + + private int GetMaxCountBetweenLayerComponents(ScadaSchemaLayerModel layer) + { + // Choose which list contains the maximum number of elements + int max = layer.Buttons.Count(); + + if (layer.Images.Count() > max) + max = layer.Images.Count(); + + if (layer.Inputs.Count() > max) + max = layer.Inputs.Count(); + + if (layer.ProgressBars.Count() > max) + max = layer.ProgressBars.Count(); + + return max; + } + + private SCADA_MEM_TYPE GetMemTypeFromString(string memType) + { + memType = memType.ToUpper(); + switch (memType) + { + case "BOOL": + return SCADA_MEM_TYPE.BOOL; + + case "BYTE": + return SCADA_MEM_TYPE.BYTE; + + case "WORD": + return SCADA_MEM_TYPE.WORD; + + case "INT": + return SCADA_MEM_TYPE.INT; + + default: + return SCADA_MEM_TYPE.BOOL; + } + } + + //DTOScadaModel scada = new DTOScadaModel + //{ + // Layers = prodScada.Layers.Select(x => new DTOScadaLayerModel() + // { + // Id = x.Id, + // Buttons = x.Buttons.Select(y => new DTOScadaButtonModel() + // { + // Id = y.Id + // }).ToList(), + // Images = x.Images.Select(y => new DTOScadaImageModel() + // { + // Id = y.Id + // }).ToList(), + // ProgressBars = x.ProgressBars.Select(y => new DTOScadaProgressBarModel() + // { + // Id = y.Id + // }).ToList(), + // Inputs = x.Inputs.Select(y => new DTOScadaInputModel() + // { + // Id = y.Id + // }).ToList() + // }).ToList() + //}; } } \ No newline at end of file diff --git a/Step/Controllers/WebApi/ScadaController.cs b/Step/Controllers/WebApi/ScadaController.cs new file mode 100644 index 00000000..bb82034b --- /dev/null +++ b/Step/Controllers/WebApi/ScadaController.cs @@ -0,0 +1,97 @@ +using CMS_CORE_Library.Models; +using Step.Model.DTOModels.Scada; +using Step.NC; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Web.Http; +using static Step.Config.ServerConfig; + +namespace Step.Controllers.WebApi +{ + [RoutePrefix("api/scada")] + public class ScadaController : ApiController + { + [Route("list")] + public IHttpActionResult GetScadaList() + { + using (NcHandler ncHandler = new NcHandler()) + { + return Ok(ConfiguredScadaSchema); + } + } + + [Route("subscribe/{scadaId:int}")] + public IHttpActionResult SubscribeScada(int scadaId) + { + // Select schema + ScadaSchemaModel selectedScadaSchema = ConfiguredScadaSchema + .Where(x => x.Id == scadaId) + .FirstOrDefault(); + + if (selectedScadaSchema == null) + return BadRequest(); + // Add to the subscriber list + SubscribedScada.Add(selectedScadaSchema); + + using (NcHandler ncHandler = new NcHandler()) + { + ncHandler.Connect(); + // Read the selected scada data + CmsError cmsError = ncHandler.ReadScadaData(selectedScadaSchema, out DTOScadaModel values); + if (cmsError.IsError()) + return BadRequest(cmsError.localizationKey); + + return Ok(values); + } + } + + [Route("unsubscribe/{scadaId:int}")] + public IHttpActionResult UnsubscribeScada(int scadaId) + { + using (NcHandler ncHandler = new NcHandler()) + { + // Find scada by id + ScadaSchemaModel scadaToRemove = SubscribedScada + .Where(x => x.Id == scadaId) + .FirstOrDefault(); + + if (scadaToRemove == null) + return BadRequest(); + // Remove from the subiscriber list + SubscribedScada.Remove(scadaToRemove); + + return Ok(); + } + } + + [Route("production")] + public IHttpActionResult GetProductionPageList() + { + using(NcHandler ncHandler = new NcHandler()) + { + ncHandler.Connect(); + CmsError cmsError = ncHandler.ReadScadasData(ProductionScadaSchema, out List values); + if (cmsError.IsError()) + return BadRequest(cmsError.localizationKey); + + + ScadaDataAndSchema data = new ScadaDataAndSchema() + { + schemes = ProductionScadaSchema, + values = values + }; + + return Ok(data); + } + } + + public class ScadaDataAndSchema + { + public List schemes; + public List values; + } + } +} diff --git a/Step/Listeners/ListenersHandler.cs b/Step/Listeners/ListenersHandler.cs index 336c2757..dacff9ec 100644 --- a/Step/Listeners/ListenersHandler.cs +++ b/Step/Listeners/ListenersHandler.cs @@ -90,8 +90,12 @@ namespace Step.Listeners { SignalRListener.SendM155Data(a); })); + infos.Add(MessageServices.Current.Subscribe(SEND_SCADA_DATA, (a, b) => + { + SignalRListener.SendScadaData(a); + })); - // Database + //////////////////////////// Database infos.Add(MessageServices.Current.Subscribe(UPDATE_TOOLS_DATA, (a, b) => { SignalRDatabaseHandler.UpdateToolsData(a); diff --git a/Step/Listeners/SignalR/SignalRListener.cs b/Step/Listeners/SignalR/SignalRListener.cs index 3d636350..44ed73b6 100644 --- a/Step/Listeners/SignalR/SignalRListener.cs +++ b/Step/Listeners/SignalR/SignalRListener.cs @@ -3,6 +3,7 @@ using Step.Config; using Step.Controllers.SignalR; using Step.Model.DTOModels; using Step.Model.DTOModels.AlarmModels; +using Step.Model.DTOModels.Scada; using Step.Model.DTOModels.ToolModels; using Step.Utils; using System; @@ -244,6 +245,19 @@ namespace Step.Listeners.SignalR } } + public static void SendScadaData(object scada) + { + List scadaVal = scada as List; + + if (!LastScadaData.SequenceEqual(scadaVal)) + { + LastScadaData = scadaVal; + + var context = GlobalHost.ConnectionManager.GetHubContext(); + context.Clients.Group("ncData").scadaData(scadaVal); + } + } + private volatile static object _broadcastlock = new Object(); public static void BroadcastData() diff --git a/Step/Listeners/SignalRStaticObjects.cs b/Step/Listeners/SignalRStaticObjects.cs index dfa6669c..715a8b77 100644 --- a/Step/Listeners/SignalRStaticObjects.cs +++ b/Step/Listeners/SignalRStaticObjects.cs @@ -1,5 +1,6 @@ using Step.Model.DTOModels; using Step.Model.DTOModels.AlarmModels; +using Step.Model.DTOModels.Scada; using Step.Model.DTOModels.ToolModels; using System.Collections.Generic; @@ -22,6 +23,7 @@ namespace Step.Listeners public static Dictionary LastNcMagazineIsActive = new Dictionary(); public static List LastPartProgramQueue = new List(); public static List LastM155Data = new List(); + public static List LastScadaData = new List(); public static bool LastIsNcConnected = false; } diff --git a/Step/Step.csproj b/Step/Step.csproj index 8ee32a58..fa433db7 100644 --- a/Step/Step.csproj +++ b/Step/Step.csproj @@ -178,6 +178,7 @@ +