Files
Mapo-IOB-WIN/IOB-WIN-NEXT/IobSoap/Gomba.cs
T
Samuele Locatelli 7cf7442420 Update simula/base
- fix comportamento reload
- test reset variabili SIMULA
2023-09-21 10:18:56 +02:00

551 lines
23 KiB
C#

using EgwProxy.Gomba.GombaServ;
using IOB_UT_NEXT;
using MapoSDK;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.NetworkInformation;
namespace IOB_WIN_NEXT.IobSoap
{
/// <summary>
/// Adapter specializzato per GOMA e le chiamate tramite WS Soap alla bilancia, libreria EgwProxy.Gomba
/// </summary>
public class Gomba : Iob.Generic
{
#region Public Constructors
/// <summary>
/// Costruttore dell'IOB SOAP della bilancia GOMBA
/// </summary>
/// <param name="caller">AdapterForm chiamante</param>
/// <param name="IOBConf">Configurazione IOB per avvio</param>
public Gomba(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf)
{
lgInfo($"Richiesto Adapter IobSoap.Gomba con i parametri seguenti | ADDR: {IOBConf.cncIpAddr} | PORT: {IOBConf.cncPort}");
redKeyPesate = redisMan.redHash($"IOB:Status:{cIobConf.codIOB}:ListPesate");
lastPING = DateTime.Now.AddHours(-1);
}
#endregion Public Constructors
#region Public Methods
/// <summary>
/// Implementazione custom esecuzione task specifici
/// </summary>
/// <param name="task2exe"></param>
/// <returns></returns>
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
{
/*---------------------------------------
* gestione execute task SPECIFICI x pesa:
* - salva i parametri richiesta (RM, cod1..cod6)
* - esegue metodo richiesta (IN/OUT)
*
*---------------------------------------*/
// Verificare il protocollo: dovrebbe togliere SOLO i task eseguiti...
Dictionary<string, string> taskDone = new Dictionary<string, string>();
if (task2exe != null)
{
lgTrace($"executeTasks: richiesta esecuzione {task2exe.Count} task");
// controllo se memMap != null...
if (memMap != null)
{
bool taskOk = false;
string taskVal = "";
// cerco task specifici: qui sono NON standard...
foreach (var item in task2exe)
{
lgInfo($"TASK | {item.Key} --> {item.Value}");
taskOk = false;
taskVal = "";
// converto richiesta in enum...
taskType tName = taskType.nihil;
Enum.TryParse(item.Key, out tName);
// controllo sulla KEY...
switch (tName)
{
case taskType.setParameter:
// richiedo da URL i parametri WRITE da popolare
lgInfo("Chiamata setParameter --> processMemWriteRequests");
taskVal = processMemWriteRequests();
// se restituiscce "" faccio altra prova...
if (string.IsNullOrEmpty(taskVal))
{
// i parametri me li aspetto come stringa composta paramName|paramvalue
if (item.Value.Contains("|"))
{
string[] paramsJob = item.Value.Split('|');
taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}";
}
else
{
taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value";
}
}
break;
default:
taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}");
break;
}
// aggiungo task!
taskDone.Add(item.Key, taskVal);
}
}
else
{
lgError($"Attenzione! memMap è nullo, non posso eseguire task2exe!");
}
}
return taskDone;
}
/// <summary>
/// Recupero dati dinamici...
/// </summary>
public override Dictionary<string, string> getDynData()
{
// valore non presente in vers default... se gestito fare override
Dictionary<string, string> outVal = new Dictionary<string, string>();
Stopwatch sw = new Stopwatch();
sw.Start();
// test lettura elenco pesate... se NON nullo --> OK!
var weightArray = gombaConn.reqWeightList("ALL", dataFrom, dataTo);
// riordino DESC
listPesateCurr = weightArray.OrderByDescending(x => x.dateIn).ToList();
sw.Stop();
lgInfo($"getDynData | SOAP: effettuata chiamata reqWeightList in {sw.Elapsed.TotalMilliseconds}ms | {dataFrom} --> {dataTo} | {listPesateCurr.Count} rec");
// verifico se ci siano pesate nuove o meno...
if (listPesateCurr.Count != listPesateArch.Count)
{
// elenco indici
List<string> listRmCurr = listPesateCurr.OrderBy(x => x.dateIn).Select(x => x.rm).ToList();
List<string> listRmArch = listPesateArch.OrderBy(x => x.dateIn).Select(x => x.rm).ToList();
// cerco nuove pesate confrontando rn archivio e curr...
List<string> listPresent = listRmCurr.Intersect(listRmArch).ToList();
foreach (var item in listPresent)
{
listRmCurr.Remove(item);
}
// aggiungo solo 1 pesata, la + vecchia...
if (listRmCurr.Count > 0)
{
// prendo la prima
var firstRec = listPesateCurr.Find(x => x.rm == listRmCurr[0]);
if (firstRec != null)
{
outVal.Add("RM", firstRec.rm);
}
// accodo x invio pesata valide IN se presenti...
if (firstRec.dateInSpecified)
{
// invio record SOLO PESO
outVal.Add("lastWeightIn", $"{firstRec.weightIn}");
// registro record completo ultima pesata
outVal.Add("lastRecIn", formatPesata(firstRec, true));
}
// accodo x invio pesata valide OUT se presenti...
if (firstRec.dateOutSpecified)
{
// invio record SOLO PESO
outVal.Add("lastWeightOut", $"{firstRec.weightIn}");
// registro record completo ultima pesata
outVal.Add("lastRecOut", formatPesata(firstRec, false));
}
// la aggiungo alle pesate archiviate...
var tmpPesate = listPesateArch;
tmpPesate.Add(firstRec);
listPesateArch = tmpPesate;
}
}
// processo comunque le aree memoria READ...
if (memMap.mMapRead.Count > 0)
{
foreach (var item in memMap.mMapRead)
{
var currVal = getCurrProdData(item.Key, "");
outVal.Add(item.Key, $"{currVal}");
}
}
lastReadPLC = DateTime.Now;
return outVal;
}
/// <summary>
/// Effettua lettura semafori principale <paramref name="currDispData">Parametri da
/// aggiornare x display in form</paramref>
/// </summary>
public override void readSemafori(ref newDisplayData currDispData)
{
if (connectionOk)
{
B_input = 1;
currDispData.semIn = Semaforo.SV;
// se ho pesate in memoria nel periodo richiesto --> RUN
if (listPesateCurr != null && listPesateCurr.Count > 0)
{
B_input += (1 << 1);
}
// metto manuale
else
{
B_input += (1 << 4);
}
// accodo NON emergenza
B_input += (1 << 7);
}
else
{
B_input = 0;
currDispData.semIn = Semaforo.SR;
}
}
/// <summary>
/// Override connessione
/// </summary>
public override void tryConnect()
{
if (!connectionOk)
{
// controllo che il ping sia stato tentato almeno pingTestSec fa...
if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec"))
{
if (verboseLog || periodicLog)
{
lgInfo("Gomba: ConnKO - tryConnect");
}
// in primis salvo data ping...
lastPING = DateTime.Now;
// se passa il ping faccio il resto...
if (testPingMachine == IPStatus.Success)
{
string szStatusConnection = "";
try
{
// ora provo connessione...
parentForm.commPlcActive = true;
// init del proxy!!!
string endpointAddr = $"https://{cIobConf.cncIpAddr}:{cIobConf.cncPort}/ws";
lgInfo($"Tentativo avvio SOAP su endpoint {endpointAddr}");
Stopwatch sw = new Stopwatch();
sw.Start();
// salto verifica certificato
System.Net.ServicePointManager.ServerCertificateValidationCallback = (senderX, certificate, chain, sslPolicyErrors) => { return true; };
// avvio!
gombaConn = new EgwProxy.Gomba.GombaServ.lwpServiceClient("lwpServicePort", new System.ServiceModel.EndpointAddress(endpointAddr));
// test lettura elenco pesate... se NON nullo --> OK!
var weightArray = gombaConn.reqWeightList("ALL", dataFrom, dataTo);
// riordino DESC
listPesateCurr = weightArray.OrderByDescending(x => x.dateIn).ToList();
sw.Stop();
lgInfo($"SOAP: effettuata chiamata reqWeightList in {sw.Elapsed.TotalMilliseconds}ms | {dataFrom} --> {dataTo}");
if (listPesateCurr != null && listPesateCurr.Count >= 0)
{
lgInfo($"szStatusConnection Gomba, recuperato elenco di {listPesateCurr.Count} pesate");
parentForm.commPlcActive = false;
connectionOk = true;
// sistemo data per recuperi successivi se ho + di 10 record...
if (listPesateCurr.Count > 10)
{
var lastRec = listPesateCurr.Skip(9).FirstOrDefault();
dtStartLive = lastRec.dateIn;
}
}
// refresh stato connessione!!!
if (connectionOk)
{
queueInEnabCurr = true;
// carico pesate da redis...
listPesatePrev = listPesateArch;
if (adpRunning)
{
lgInfo("Connessione OK");
}
}
else
{
lgError("Impossibile procedere, connessione mancante...");
}
}
catch (Exception exc)
{
lgFatal($"Errore nella connessione all'adapter Gomba: {szStatusConnection}{Environment.NewLine}{exc}");
connectionOk = false;
lgInfo($"Eccezione in TryConnect, Adapter Gomba NON running, pausa di {utils.CRI("waitRecMSec")} msec prima di ulteriori tentativi di riconnessione");
}
}
else
{
// loggo no risposta ping ...
connectionOk = false;
if (verboseLog || periodicLog)
{
lgInfo($"Attenzione: Gomba controllo PING fallito per IP {cIobConf.cncPingAddr}");
}
}
}
}
else
{
needRefresh = true;
}
}
public override void tryDisconnect()
{
// registro solo che è disconnesso
connectionOk = false;
queueInEnabCurr = false;
}
#endregion Public Methods
#region Protected Fields
/// <summary>
/// Proxy per connessione al SOAP webservice GOMBA
/// </summary>
protected EgwProxy.Gomba.GombaServ.lwpServiceClient gombaConn;
#endregion Protected Fields
#region Protected Methods
/// <summary>
/// Metodo da overridare x scrivere DAVVERO i parametri sul PLC
/// </summary>
/// <param name="updatedPar"></param>
protected override void plcWriteParams(ref List<objItem> updatedPar)
{
lgTrace($"plcWriteParams: richiesta per {updatedPar.Count} params");
foreach (var item in updatedPar)
{
lgInfo($"ITEM | {item.uid} | {item.value}");
// salvo i valori di setup x prox pesata...
upsertKey(item.uid, item.value);
bool fatto = false;
bool isPesata = false;
bool isIN = false;
gestWeightOut answ = new gestWeightOut();
// se è richiesta pesata IN/OUT --> mando chiamata
if (item.uid == "reqPesata")
{
isPesata = true;
isIN = item.value.ToUpper() == "IN";
answ = reqWeight(isIN);
}
else if (item.uid == "RM" || item.uid.StartsWith("Cod"))
{
// comunque segno fatto x altri casi
fatto = true;
}
// se è pesata...
if (isPesata)
{
// se è OK
if (answ.feedback == "C")
{
string recPesata = formatPesata(answ, item.uid == "reqIN");
lgInfo($"reqWeight | OK effettuato pesata | {recPesata}");
// aggiorno dati pesate IN/OUT...
if(isIN)
{
upsertKey("lastWeightIn", answ.weightIn);
upsertKey("lastRecIn", recPesata);
}
else
{
upsertKey("lastWeightOut", answ.weightOut);
upsertKey("lastRecOut", recPesata);
}
}
else
{
lgError($"reqWeight | Errore in richiesta peso GOMBA | {answ.feedback} | {answ.notes}");
}
item.value = "";
//item.value = $"{answ.feedback} | {answ.notes}";
item.reqValue = "";
item.lastRead = DateTime.Now;
item.UM = "";
// salvo esito richiesta comunque
upsertKey("logReq", $"{answ.feedback} | {answ.notes}");
// faccio in modo di eseguire subito getDynData
demFactDynData = 1;
}
else
{
// se fatto --> aggiorno!
if (fatto)
{
//item.value = item.reqValue;
item.reqValue = "";
item.lastRead = DateTime.Now;
item.UM = "";
}
}
}
}
/// <summary>
/// Esegue richiesta PESO
/// </summary>
/// <param name="reqIN">Tipo richiesta: IN (true) / OUT (false)</param>
/// <returns></returns>
protected gestWeightOut reqWeight(bool reqIN)
{
lgInfo($"reqWeight | IN: {reqIN}");
gestWeightOut answ = null;
try
{
Stopwatch sw = new Stopwatch();
sw.Start();
// preparo parametri
string tipoRic = reqIN ? "IN" : "OUT";
string rm = getCurrProdData("RM", $"{DateTime.Now:yyyyMMdd-HHmmss}");// string.IsNullOrEmpty(currProdData["RM"]) ? $"{DateTime.Now:yyyyMMdd-HHmmss}" : currProdData["RM"];
string Cod1 = getCurrProdData("Cod1", ""); //string.IsNullOrEmpty(currProdData["Cod1"]) ? "" : currProdData["Cod1"];
string Cod2 = getCurrProdData("Cod2", ""); //string.IsNullOrEmpty(currProdData["Cod2"]) ? "" : currProdData["Cod2"];
string Cod3 = getCurrProdData("Cod3", ""); //string.IsNullOrEmpty(currProdData["Cod3"]) ? "" : currProdData["Cod3"];
string Cod4 = getCurrProdData("Cod4", ""); //string.IsNullOrEmpty(currProdData["Cod4"]) ? "" : currProdData["Cod4"];
string Cod5 = getCurrProdData("Cod5", ""); //string.IsNullOrEmpty(currProdData["Cod5"]) ? "" : currProdData["Cod5"];
string Cod6 = getCurrProdData("Cod6", ""); //string.IsNullOrEmpty(currProdData["Cod6"]) ? "" : currProdData["Cod6"];
// faccio chiamata
answ = gombaConn.memWeight(tipoRic, rm, Cod1, Cod2, Cod3, Cod4, Cod5, Cod6);
sw.Stop();
lgInfo($"reqWeight: effettuata chiamata SOAP in {sw.Elapsed.TotalMilliseconds}ms | {dataFrom} --> {dataTo}");
}
catch (Exception exc)
{
lgError($"reqWeight | errore richiesta pesatura{Environment.NewLine}{exc}");
}
return answ;
}
#endregion Protected Methods
#region Private Properties
/// <summary>
/// Data inizio periodo dati Bilancia:
/// - al boot impostato a -6 mesi
/// - dopo lettura impostato a data ultimi 5 record
/// </summary>
private string dataFrom
{
get => dtStartLive.ToString("dd/MM/yyyy");
}
/// <summary>
/// Data fine periodo dati Bilancia: oggi + 1gg
/// </summary>
private string dataTo
{
get => DateTime.Today.AddDays(1).ToString("dd/MM/yyyy");
}
private DateTime dtStartLive { get; set; } = DateTime.Today.AddMonths(-6);
/// <summary>
/// Gestione archivio serializzato delle pesate già processate
/// </summary>
private List<EgwProxy.Gomba.GombaServ.gestWeightOut> listPesateArch
{
get
{
List<EgwProxy.Gomba.GombaServ.gestWeightOut> answ = new List<EgwProxy.Gomba.GombaServ.gestWeightOut>();
string rawData = redisMan.getRSV(redKeyPesate);
if (!string.IsNullOrEmpty(rawData))
{
try
{
answ = JsonConvert.DeserializeObject<List<EgwProxy.Gomba.GombaServ.gestWeightOut>>(rawData);
lgInfo($"Rilettura status listPesateArch: trovati {answ.Count} record");
}
catch (Exception exc)
{
lgError($"Errore in deserializzazione listPesateArch{Environment.NewLine}{exc}");
answ = new List<EgwProxy.Gomba.GombaServ.gestWeightOut>();
}
}
return answ;
}
set
{
string rawVal = JsonConvert.SerializeObject(value);
redisMan.setRSV(redKeyPesate, rawVal);
lgInfo($"Salvataggio status listPesateArch | {value.Count} record");
}
}
/// <summary>
/// Elenco pesate attuali
/// </summary>
private List<EgwProxy.Gomba.GombaServ.gestWeightOut> listPesateCurr { get; set; } = new List<EgwProxy.Gomba.GombaServ.gestWeightOut>();
/// <summary>
/// Elenco lettura pesate precedenti
/// </summary>
private List<EgwProxy.Gomba.GombaServ.gestWeightOut> listPesatePrev { get; set; } = new List<EgwProxy.Gomba.GombaServ.gestWeightOut>();
private string redKeyPesate { get; set; } = "";
#endregion Private Properties
#region Private Methods
private static string formatCode(string currCode)
{
string code = string.IsNullOrEmpty(currCode) ? "-" : currCode;
return $" | {code}";
}
/// <summary>
/// Formatta record completo pesata
/// </summary>
/// <param name="rec">record completo pesate Gomba</param>
/// <param name="isIN">Indica se deve formattare i dati tipo IN (true) o OUT (false)</param>
/// <returns></returns>
private static string formatPesata(gestWeightOut rec, bool isIN)
{
string currVal = "";
if (isIN)
{
currVal = $"{rec.dateIn:yyyy-MM-dd HH:mm:ss} | {rec.weightIn} kg";
}
else
{
currVal = $"{rec.dateOut:yyyy-MM-dd HH:mm:ss} | {rec.weightOut} kg";
}
currVal += formatCode(rec.cod1);
currVal += formatCode(rec.cod2);
currVal += formatCode(rec.cod3);
currVal += formatCode(rec.cod4);
currVal += formatCode(rec.cod5);
currVal += formatCode(rec.cod6);
return currVal;
}
#endregion Private Methods
}
}