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..b9c4c7be 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,109 @@ 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)) + { + // check filePath... + if (!filePath.Contains(RECIPE_DIRECTORY)) + { + // aggiungo base path! + filePath = RECIPE_DIRECTORY + 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); + // check filePath... + if (!filePath.Contains(RECIPE_DIRECTORY)) + { + // aggiungo base path! + filePath = RECIPE_DIRECTORY + filePath; + } + // 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/NcAdapter.cs b/Thermo.Active.NC/NcAdapter.cs index 9efc234e..1b79e3f7 100644 --- a/Thermo.Active.NC/NcAdapter.cs +++ b/Thermo.Active.NC/NcAdapter.cs @@ -1621,15 +1621,11 @@ namespace Thermo.Active.NC CmsError cmsError = NO_ERROR; currOverview = new Dictionary(); - // !!!FARE davvero!!! -#if false - // gestione errore - cmsError = ReadScadaData(schema, out currParam); + // leggo la ricetta! + var currRecipe = new Dictionary(); + cmsError = ReadFullRecipe(out currRecipe); if (cmsError.IsError()) - return cmsError; -#endif - - // calcolo! + return cmsError; // leggo l'intero array delle DB... QUI FAKE sulle DB configurate... List recipeConfig = RecipeConfig.Select(x => new DTORecipeConfigModel() @@ -1645,34 +1641,51 @@ namespace Thermo.Active.NC }).ToList(); RecipeCatStatus currStatus = RecipeCatStatus.Unchanged; - int countCat = 0; + + // percorro conf ricetta... foreach (var item in recipeConfig) { - // ogni 20 incremento... - if (countCat < 20) + currStatus = RecipeCatStatus.Unchanged; + // cerco SE ci sia già uno status... + if (currOverview.ContainsKey(item.Category)) { - currStatus = RecipeCatStatus.Unchanged; + currStatus = currOverview[item.Category]; } - else if (countCat < 40) + + // se lo stato è errore --> esco... + if (currStatus == RecipeCatStatus.HasError) { - currStatus = RecipeCatStatus.ChangedOk; + continue; } + // altrimenti controllo else { - currStatus = RecipeCatStatus.HasError; + // se in errore --> registro... + if (currRecipe[item.Label].Status.HasError) + { + currStatus = RecipeCatStatus.HasError; + } + // FARE verificare il significato di questo changed (se è da file o da HMI/PLC) + else if (currRecipe[item.Label].SetpointHMI != currRecipe[item.Label].SetpointPLC) + { + currStatus = RecipeCatStatus.ChangedOk; + } + else + { + currStatus = RecipeCatStatus.Unchanged; + } } - // se non c'è aggiungo + + // ora verifico overview finale: se non c'è aggiungo if (!currOverview.ContainsKey(item.Category)) { currOverview.Add(item.Category, currStatus); - countCat = 0; } else { // se il valore è maggiore --> aggiorno currOverview[item.Category] = (int)currStatus > (int)currOverview[item.Category] ? currStatus : currOverview[item.Category]; } - countCat++; } // restituisco cod errore se trovato @@ -1731,6 +1744,28 @@ namespace Thermo.Active.NC return cmsError; } + /// + /// Returns resistances configuration + /// + /// List of configured resistances + /// + public CmsError GetWarmersResistances(out Dictionary currWarmersResistances) + { + CmsError cmsError = NO_ERROR; + currWarmersResistances = new Dictionary(); + + // read and return config + if (NcConfig.NcVendor == NC_VENDOR.S7NET) + { + foreach (var item in RiskResistConfig) + { + currWarmersResistances.Add(item.Id, item); + } + } + + // restituisco cod errore se trovato + return cmsError; + } #endregion Read Data 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 92614144..8466f6a0 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 { @@ -54,8 +55,6 @@ namespace Thermo.Active.Controllers.WebApi } } - - [Route("update"), HttpPut] public IHttpActionResult WriteParameters(Dictionary parametersList) { @@ -116,6 +115,23 @@ namespace Thermo.Active.Controllers.WebApi if (cmsError.IsError()) return BadRequest(cmsError.localizationKey); + // recupero i dati LIVE dei parametri HMI della ricetta... + cmsError = ncAdapter.ReadFullRecipe(out Dictionary currRecipe); + if (cmsError.IsError()) + return BadRequest(cmsError.localizationKey); + + // rileggo la ricetta + 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(); + // ritorno solo fatto! return Ok(); } @@ -140,11 +156,117 @@ namespace Thermo.Active.Controllers.WebApi if (cmsError.IsError()) return BadRequest(cmsError.localizationKey); + // recupero i dati LIVE dei parametri HMI della ricetta... + 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(); + // 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(); + + // 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(); + + // 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(); + + // 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.SaveRecipe(newName); + + // 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(); + if (libraryError.errorCode != 0) + return NotFound(); + + // chiamo metodo di lettura... + ServerConfigController.LoadRecipe(newName); + + // ritorno solo fatto! + return Ok(); + } + } } } \ No newline at end of file diff --git a/Thermo.Active/Controllers/WebApi/WarmersController.cs b/Thermo.Active/Controllers/WebApi/WarmersController.cs index f437f5b5..595fd2bc 100644 --- a/Thermo.Active/Controllers/WebApi/WarmersController.cs +++ b/Thermo.Active/Controllers/WebApi/WarmersController.cs @@ -19,8 +19,8 @@ namespace Thermo.Active.Controllers.WebApi [RoutePrefix("api/warmers")] public class WarmersController : ApiController { - [Route("current"), HttpGet] - public IHttpActionResult GetCurrentWarmers() + [Route("channels"), HttpGet] + public IHttpActionResult GetCurrentWarmersChannels() { using (NcAdapter ncAdapter = new NcAdapter()) { @@ -36,18 +36,39 @@ namespace Thermo.Active.Controllers.WebApi return Ok(currWarmers); } } - - - // FIXME TODO determinare IN PRIMIS nel modello COSA e come aggiornare... -#if false - [Route("update"), HttpPut] - public IHttpActionResult WriteWarmers(Dictionary parametersList) + [Route("resistances"), HttpGet] + public IHttpActionResult GetCurrentWarmersResistances() { using (NcAdapter ncAdapter = new NcAdapter()) { // Try connection CmsError libraryError = ncAdapter.Connect(); + if (libraryError.errorCode != 0) + return NotFound(); + CmsError cmsError = ncAdapter.GetWarmersResistances(out Dictionary currWarmers); + if (cmsError.IsError()) + return BadRequest(cmsError.localizationKey); + + return Ok(currWarmers); + } + } + + + [Route("update"), HttpPut] + public IHttpActionResult WriteSetpoints(Dictionary channelsList) + { + // scrive su CHp da ricetta oppure da override x parametri utente... + + using (NcAdapter ncAdapter = new NcAdapter()) + { +#if false + // Try connection + CmsError libraryError = ncAdapter.Connect(); + if (libraryError.errorCode != 0) + return NotFound(); + + // read recipe! CmsError cmsError = ncAdapter.ReadFullRecipe(out Dictionary prevRecipe); if (cmsError.IsError()) return BadRequest(cmsError.localizationKey); @@ -71,13 +92,66 @@ namespace Thermo.Active.Controllers.WebApi } // scrivo sul PLC - ncAdapter.WriteRecipeParams(updtRecipe); + ncAdapter.WriteRecipeParams(updtRecipe); +#endif // ritorno solo fatto! return Ok(); } - } + } + + /// + /// Confirm recipe modification (parameters: HMI --> PLC) + /// + /// + [Route("confirm"), HttpPut] + public IHttpActionResult ConfirmEdit() + { + using (NcAdapter ncAdapter = new NcAdapter()) + { +#if false + // Try connection + CmsError libraryError = ncAdapter.Connect(); + if (libraryError.errorCode != 0) + return NotFound(); + + // scrivo sul PLC il comando conferma! + CmsError cmsError = ncAdapter.ConfirmRecipeData(true); + if (cmsError.IsError()) + return BadRequest(cmsError.localizationKey); #endif + // ritorno solo fatto! + return Ok(); + } + } + + /// + /// Cancel recipe modification (parameters: PLC --> HMI) + /// + /// + [Route("cancel"), HttpPut] + public IHttpActionResult CancelEdit() + { + using (NcAdapter ncAdapter = new NcAdapter()) + { +#if false + // 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); +#endif + + // ritorno solo fatto! + return Ok(); + } + } + + } } \ No newline at end of file