From 020d8304a57824e6c16c84fb3ccafc41b6b7fbe6 Mon Sep 17 00:00:00 2001 From: Samuele Locatelli Date: Fri, 5 Jun 2020 23:13:46 +0200 Subject: [PATCH] DRAFT: Recipe local persistence file --- Thermo.Active.Config/LiveData.cs | 28 +++++ Thermo.Active.Config/ServerConfig.cs | 16 ++- .../ServerConfigController.cs | 90 +++++++++++++- .../Thermo.Active.Config.csproj | 10 ++ Thermo.Active.Config/packages.config | 4 + Thermo.Active.Model/Constants.cs | 3 + Thermo.Active.NC/NcFileAdapter.cs | 59 ++++++++- .../Controllers/WebApi/RecipeController.cs | 114 +++++++++++++++++- 8 files changed, 310 insertions(+), 14 deletions(-) create mode 100644 Thermo.Active.Config/LiveData.cs create mode 100644 Thermo.Active.Config/packages.config diff --git a/Thermo.Active.Config/LiveData.cs b/Thermo.Active.Config/LiveData.cs new file mode 100644 index 00000000..e729d7d3 --- /dev/null +++ b/Thermo.Active.Config/LiveData.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Thermo.Active.Config +{ + /// + /// Live data for Thermo Active + /// + public class LiveData + { + /// + /// Current loaded recipe + /// + public string RecipeName = "current.json"; + /// + /// Dictionary of all parameters and values + /// + public Dictionary RecipeParameters; + /// + /// Dictionary of all channels and relative setpoints + /// + public Dictionary ChannelSetpoints; + + } +} diff --git a/Thermo.Active.Config/ServerConfig.cs b/Thermo.Active.Config/ServerConfig.cs index e18c1028..3cc50e77 100644 --- a/Thermo.Active.Config/ServerConfig.cs +++ b/Thermo.Active.Config/ServerConfig.cs @@ -32,10 +32,8 @@ namespace Thermo.Active.Config public static List NcSoftKeysConfig; public static List InitialAlarmsConfig; public static List HeadsConfig; - public static List RecipeConfig; - public static List ModBlockConfig; - public static List RiskResistConfig; - public static List RiskChannelConfig; + + public static CmsConnectConfigModel CmsConnectConfig; public static AreasConfigModel ProductionConfig; @@ -55,5 +53,15 @@ namespace Thermo.Active.Config public static List MacrosConfig; public static string CMSMainProgramContent; + + + // Thermo + public static List RecipeConfig; + public static List ModBlockConfig; + public static List RiskResistConfig; + public static List RiskChannelConfig; + + public static LiveData RecipeLiveData; } + } \ No newline at end of file diff --git a/Thermo.Active.Config/ServerConfigController.cs b/Thermo.Active.Config/ServerConfigController.cs index 86c811d4..5cfaad83 100644 --- a/Thermo.Active.Config/ServerConfigController.cs +++ b/Thermo.Active.Config/ServerConfigController.cs @@ -15,6 +15,7 @@ using System.Xml.Serialization; using static Thermo.Active.Config.ServerConfig; using static Thermo.Active.Model.Constants; using static Thermo.Active.Utils.SupportFunctions; +using Newtonsoft.Json; namespace Thermo.Active.Config { @@ -39,7 +40,7 @@ namespace Thermo.Active.Config // ReadCMSConnectConfig(); ReadMacros(); ReadScadaFile(); - //ReadMainProgram(); + ReadLiveData(); } catch (XmlException ex) { @@ -687,7 +688,7 @@ namespace Thermo.Active.Config { // cerco il TIPO... var riferimento = Riferimenti.Find(x => x.Id == resistenza.Tipo); - if(riferimento!=null) + if (riferimento != null) { RiskChannelConfig.Add(new RiskChannelModel() { @@ -790,15 +791,96 @@ namespace Thermo.Active.Config .Select(x => x.Value) .ToList(); } + /// + /// Try to load live data from json persistence file + /// + public static void ReadLiveData() + { + if (File.Exists(LIVE_RECIPE_PATH)) + { + // load all text data + var rawData = File.ReadAllText(LIVE_RECIPE_PATH); + try + { + // deserialize to object + RecipeLiveData = JsonConvert.DeserializeObject(rawData); + } + catch + { } + } + else + { + // setup new object + RecipeLiveData = new LiveData() + { + RecipeName = "current.json", + ChannelSetpoints = new Dictionary(), + RecipeParameters = new Dictionary() + }; + } + } + /// + /// Try to write live data to json persistence file + /// + public static void WriteLiveData() + { + try + { + // serialize + string rawData = JsonConvert.SerializeObject(RecipeLiveData); + // save live! + File.WriteAllText(LIVE_RECIPE_PATH, rawData); + } + catch + { } + } + /// + /// Try to load selected recipe to live data (memory and json persistence file) + /// + public static void LoadRecipe(string filePath) + { + if (File.Exists(filePath)) + { + // load all text data + var rawData = File.ReadAllText(filePath); + try + { + // deserialize to object + RecipeLiveData = JsonConvert.DeserializeObject(rawData); + } + catch + { } + // update current live data! + WriteLiveData(); + } + } + /// + /// Try to save live recipe to selected filePath + /// + public static void SaveRecipe(string filePath) + { + try + { + // serialize + string rawData = JsonConvert.SerializeObject(RecipeLiveData); + // save live! + File.WriteAllText(LIVE_RECIPE_PATH, rawData); + // save! + File.WriteAllText(filePath, rawData); + } + catch + { } + } - +#if false public static void ReadMainProgram() { if (File.Exists(MAIN_PROGRAM_CONFIG_PATH)) { CMSMainProgramContent = File.ReadAllText(MAIN_PROGRAM_CONFIG_PATH); } - } + } +#endif public static string CalculateHash(string filename) { diff --git a/Thermo.Active.Config/Thermo.Active.Config.csproj b/Thermo.Active.Config/Thermo.Active.Config.csproj index 27d70235..59b4e97b 100644 --- a/Thermo.Active.Config/Thermo.Active.Config.csproj +++ b/Thermo.Active.Config/Thermo.Active.Config.csproj @@ -32,6 +32,9 @@ 4 + + ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll + @@ -52,6 +55,7 @@ Designer PreserveNewest + @@ -175,5 +179,11 @@ Designer + + + + + + \ No newline at end of file diff --git a/Thermo.Active.Config/packages.config b/Thermo.Active.Config/packages.config new file mode 100644 index 00000000..7c080311 --- /dev/null +++ b/Thermo.Active.Config/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Thermo.Active.Model/Constants.cs b/Thermo.Active.Model/Constants.cs index 480e679d..fb3022fa 100644 --- a/Thermo.Active.Model/Constants.cs +++ b/Thermo.Active.Model/Constants.cs @@ -210,6 +210,7 @@ namespace Thermo.Active.Model public static string WEBSITE_DIRECTORY = BASE_PATH + "\\view"; #endif public const string CONFIG_DIRECTORY = "Config\\"; + public const string RECIPE_DIRECTORY = "Recipes\\"; public const string RESOURCE_DIRECTORY = @"Thermo.Active.Config.Config."; public const string SERVER_CONFIG_SCHEMA_PATH = RESOURCE_DIRECTORY + @"serverConfigValidator.xsd"; public const string SERVER_CONFIG_PATH = CONFIG_DIRECTORY + "serverConfig.xml"; @@ -252,6 +253,8 @@ namespace Thermo.Active.Model public const string MAIN_PROGRAM_CONFIG_PATH = CONFIG_DIRECTORY + "customMainProgram.txt"; + public const string LIVE_RECIPE_PATH = RECIPE_DIRECTORY + "current.json"; + public static string LANGUAGE_PACK_DIRECTORY = BASE_PATH + "\\languages\\"; public static string LANGUAGE_SCHEMA_PATH = BASE_PATH + "\\LanguageValidator.xsd"; diff --git a/Thermo.Active.NC/NcFileAdapter.cs b/Thermo.Active.NC/NcFileAdapter.cs index 34ea08f7..83366ebf 100644 --- a/Thermo.Active.NC/NcFileAdapter.cs +++ b/Thermo.Active.NC/NcFileAdapter.cs @@ -19,6 +19,61 @@ namespace Thermo.Active.NC { public class NcFileAdapter : NcAdapter { + /// + /// Read file from local devices ad give back string content + /// + /// + /// + /// + public CmsError ReadFileContent(string path, out string fileContent) + { + // init + fileContent = ""; + if (!string.IsNullOrEmpty(path)) + { + // check existing + if (File.Exists(path)) + { + // read all lines as string + fileContent = File.ReadAllText(path); + } + else + { + return FILE_NOT_FOUND_ERROR; + } + } + else + { + return FILE_NOT_FOUND_ERROR; + } + + return NO_ERROR; + } + /// + /// Save string content to file + /// + /// + /// + /// + public CmsError WriteFileContent(string path, string fileContent) + { + if (!string.IsNullOrEmpty(path)) + { + if (!string.IsNullOrEmpty(fileContent)) + { + File.WriteAllText(path, fileContent); + } + } + else + { + return FILE_NOT_FOUND_ERROR; + } + + return NO_ERROR; + } + + + public CmsError GetFileList(string path, out List fileList) { fileList = new List(); @@ -41,8 +96,8 @@ namespace Thermo.Active.NC if (cmsError.IsError()) return cmsError; - string [] names = fileInfo.Name.Split('/'); - if(names.Length > 0) + string[] names = fileInfo.Name.Split('/'); + if (names.Length > 0) { string name = names.Last(); if (!String.IsNullOrWhiteSpace(name)) diff --git a/Thermo.Active/Controllers/WebApi/RecipeController.cs b/Thermo.Active/Controllers/WebApi/RecipeController.cs index 6c26cf03..7765b2ed 100644 --- a/Thermo.Active/Controllers/WebApi/RecipeController.cs +++ b/Thermo.Active/Controllers/WebApi/RecipeController.cs @@ -13,6 +13,7 @@ using static CMS_CORE_Library.Models.DataStructures; using static Thermo.Active.Config.ServerConfig; using static Thermo.Active.Model.Constants; using Thermo.Active.Model.DTOModels.Recipe; +using Thermo.Active.Config; namespace Thermo.Active.Controllers.WebApi { @@ -99,7 +100,7 @@ namespace Thermo.Active.Controllers.WebApi /// Confirm recipe modification (parameters: HMI --> PLC) /// /// - [Route("confirm"), HttpPut] + [Route("Confirm"), HttpPut] public IHttpActionResult ConfirmEdit() { using (NcAdapter ncAdapter = new NcAdapter()) @@ -109,8 +110,24 @@ namespace Thermo.Active.Controllers.WebApi if (libraryError.errorCode != 0) return NotFound(); + // recupero i dati LIVE dei parametri HMI della ricetta... + CmsError cmsError = ncAdapter.ReadFullRecipe(out Dictionary currRecipe); + if (cmsError.IsError()) + return BadRequest(cmsError.localizationKey); + + var currParams = new Dictionary(); + foreach (var item in currRecipe) + { + currParams.Add(item.Key, item.Value.SetpointHMI); + } + + // ora salvo ANCHE i dati live... + RecipeLiveData.RecipeParameters = currParams; + // e salvo su disco + ServerConfigController.WriteLiveData(); + // scrivo sul PLC il comando conferma! - CmsError cmsError = ncAdapter.ConfirmRecipeData(true); + cmsError = ncAdapter.ConfirmRecipeData(true); if (cmsError.IsError()) return BadRequest(cmsError.localizationKey); @@ -123,10 +140,100 @@ namespace Thermo.Active.Controllers.WebApi /// Cancel recipe modification (parameters: PLC --> HMI) /// /// - [Route("cancel"), HttpPut] + [Route("Cancel"), HttpPut] public IHttpActionResult CancelEdit() { using (NcAdapter ncAdapter = new NcAdapter()) + { + // Try connection + CmsError libraryError = ncAdapter.Connect(); + if (libraryError.errorCode != 0) + return NotFound(); + + + // recupero i dati LIVE dei parametri HMI della ricetta... + CmsError cmsError = ncAdapter.ReadFullRecipe(out Dictionary currRecipe); + if (cmsError.IsError()) + return BadRequest(cmsError.localizationKey); + + var currParams = new Dictionary(); + foreach (var item in currRecipe) + { + currParams.Add(item.Key, item.Value.SetpointPLC); + } + + // ora salvo ANCHE i dati live... + RecipeLiveData.RecipeParameters = currParams; + // e salvo su disco + ServerConfigController.WriteLiveData(); + + // scrivo sul PLC il comando annula! + cmsError = ncAdapter.ConfirmRecipeData(false); + if (cmsError.IsError()) + return BadRequest(cmsError.localizationKey); + + // ritorno solo fatto! + return Ok(); + } + } + + /// + /// Save current recipe from PLC to default + /// + /// + [Route("Save"), HttpPut] + public IHttpActionResult Save() + { + using (NcFileAdapter ncAdapter = new NcFileAdapter()) + { + // Try connection + CmsError libraryError = ncAdapter.Connect(); + if (libraryError.errorCode != 0) + return NotFound(); + + // serialize current recipe as JSon + + //// scrivo sul PLC il comando annula! + //CmsError cmsError = ncAdapter.ConfirmRecipeData(false); + //if (cmsError.IsError()) + // return BadRequest(cmsError.localizationKey); + + // ritorno solo fatto! + return Ok(); + } + } + + /// + /// Save current recipe from PLC with new name + /// + /// + [Route("SaveAs"), HttpPut] + public IHttpActionResult SaveAs(string newName) + { + using (NcFileAdapter ncAdapter = new NcFileAdapter()) + { + // Try connection + CmsError libraryError = ncAdapter.Connect(); + if (libraryError.errorCode != 0) + return NotFound(); + + // scrivo sul PLC il comando annula! + CmsError cmsError = ncAdapter.ConfirmRecipeData(false); + if (cmsError.IsError()) + return BadRequest(cmsError.localizationKey); + + // ritorno solo fatto! + return Ok(); + } + } + /// + /// load recipe from file and send to PLC + /// + /// + [Route("Load"), HttpPut] + public IHttpActionResult Load(string newName) + { + using (NcFileAdapter ncAdapter = new NcFileAdapter()) { // Try connection CmsError libraryError = ncAdapter.Connect(); @@ -143,6 +250,5 @@ namespace Thermo.Active.Controllers.WebApi } } - } } \ No newline at end of file