Merge branch 'release/OpcSiemensRama11'

This commit is contained in:
Samuele Locatelli
2024-11-29 12:10:22 +01:00
9 changed files with 380 additions and 111 deletions
+1 -1
View File
@@ -49,7 +49,7 @@ CLI_INST=SteamWareSim
;NB: mettere copy always ai file di conf x fare test...
;STARTLIST=SIMUL_01
STARTLIST=Tend_RAMA_100_47
STARTLIST=Tend_RAMA_10_47
MAXCNC=10
@@ -70,9 +70,9 @@ READ_ERROR_MAX=10
READ_ERROR_SLEEP_TIME=30000
MAX_ERR_CHECK=400
; conf parametri memoria READ/WRITE
OPC_PARAM_CONF=Tend_RAMA_100_47.json
OPC_PARAM_CONF=Tend_RAMA_10_47.json
;; conf aree allarme
;ALARM_CONF=Tend_RAMA_100_47_alarm.json
;ALARM_CONF=Tend_RAMA_10_47_alarm.json
ENABLE_MEM_REWRITE=FALSE
[BRANCH]
@@ -813,240 +813,178 @@
"OPC_SP_FabSpeed_ChainSpeed": {
"name": "OPC_SP_FabSpeed_ChainSpeed",
"description": "Chain Speed",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fabric Transport\"#Chain Speed - m_min",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fabric Transport\"#Chain Speed - m_min"
},
"OPC_SP_FabSpeed_TOffOverFeed": {
"name": "OPC_SP_FabSpeed_TOffOverFeed",
"description": "TakeOff Overfeeding",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fabric Transport\"#Take Off Overfeeding - %",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fabric Transport\"#Take Off Overfeeding - %"
},
"OPC_SP_Spind_WidthMast": {
"name": "OPC_SP_Spind_WidthMast",
"description": "Width Master",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Width Master - cm",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Width Master - cm"
},
"OPC_SP_Spind_WidthV1": {
"name": "OPC_SP_Spind_WidthV1",
"description": "Diff V1",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Differentiation V1 - cm",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Differentiation V1 - cm"
},
"OPC_SP_Spind_WidthV2": {
"name": "OPC_SP_Spind_WidthV2",
"description": "Diff V2",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Differentiation V2 - cm",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Differentiation V2 - cm"
},
"OPC_SP_Spind_WidthV3": {
"name": "OPC_SP_Spind_WidthV3",
"description": "Diff V3",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Differentiation V3 - cm",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Differentiation V3 - cm"
},
"OPC_SP_Spind_WidthV4": {
"name": "OPC_SP_Spind_WidthV4",
"description": "Diff V4",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Differentiation V4 - cm",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Differentiation V4 - cm"
},
"OPC_SP_Spind_WidthV5": {
"name": "OPC_SP_Spind_WidthV5",
"description": "Diff V5",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Differentiation V5 - cm",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Differentiation V5 - cm"
},
"OPC_SP_Spind_WidthV6": {
"name": "OPC_SP_Spind_WidthV6",
"description": "Diff V6",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Differentiation V6 - cm",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Differentiation V6 - cm"
},
"OPC_SP_Spind_WidthV7": {
"name": "OPC_SP_Spind_WidthV7",
"description": "Diff V7",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Differentiation V7 - cm",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Width\"#Differentiation V7 - cm"
},
"OPC_SP_OvenSpeedCoolCell1": {
"name": "OPC_SP_OvenSpeedCoolCell1",
"description": "Cooling Fan",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Cooling Fan 1 - %",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Cooling Fan 1 - %"
},
"OPC_SP_OvenSpeedExFan1": {
"name": "OPC_SP_OvenSpeedExFan1",
"description": "Exhaust Fan 1",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Exaust Fan 1 - %",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Exaust Fan 1 - %"
},
"OPC_SP_OvenSpeedExFan2": {
"name": "OPC_SP_OvenSpeedExFan2",
"description": "Exhaust Fan 2",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Exaust Fan 2 - %",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Exaust Fan 2 - %"
},
"OPC_SP_OvenSpeedFan101": {
"name": "OPC_SP_OvenSpeedFan101",
"description": "Fan V1",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V1 - %",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V1 - %"
},
"OPC_SP_OvenSpeedFan101A": {
"name": "OPC_SP_OvenSpeedFan101A",
"description": "Fan V1A",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V1A - %",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V1A - %"
},
"OPC_SP_OvenSpeedFan103": {
"name": "OPC_SP_OvenSpeedFan103",
"description": "Fan V2",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V2 - %",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V2 - %"
},
"OPC_SP_OvenSpeedFan103A": {
"name": "OPC_SP_OvenSpeedFan103A",
"description": "Fan V2A",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V2A - %",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V2A - %"
},
"OPC_SP_OvenSpeedFan105": {
"name": "OPC_SP_OvenSpeedFan105",
"description": "Fan V3",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V3 - %",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V3 - %"
},
"OPC_SP_OvenSpeedFan105A": {
"name": "OPC_SP_OvenSpeedFan105A",
"description": "Fan V3A",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V3A - %",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V3A - %"
},
"OPC_SP_OvenSpeedFan107": {
"name": "OPC_SP_OvenSpeedFan107",
"description": "Fan V4",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V4 - %",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V4 - %"
},
"OPC_SP_OvenSpeedFan107A": {
"name": "OPC_SP_OvenSpeedFan107A",
"description": "Fan V4A",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V4A - %",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V4A - %"
},
"OPC_SP_OvenSpeedFan109": {
"name": "OPC_SP_OvenSpeedFan109",
"description": "Fan V5",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V5 - %",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V5 - %"
},
"OPC_SP_OvenSpeedFan109A": {
"name": "OPC_SP_OvenSpeedFan109A",
"description": "Fan V5A",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V5A - %",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Fans\"#Fan V5A - %"
},
"OPC_SP_Temp_Burner1": {
"name": "OPC_SP_Temp_Burner1",
"description": "Burner 1",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 1 Temperature - °C",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 1 Temperature - °C"
},
"OPC_SP_Temp_Burner2": {
"name": "OPC_SP_Temp_Burner2",
"description": "Burner 2",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 2 Temperature - °C",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 2 Temperature - °C"
},
"OPC_SP_Temp_Burner3": {
"name": "OPC_SP_Temp_Burner3",
"description": "Burner 3",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 3 Temperature - °C",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 3 Temperature - °C"
},
"OPC_SP_Temp_Burner4": {
"name": "OPC_SP_Temp_Burner4",
"description": "Burner 4",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 4 Temperature - °C",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 4 Temperature - °C"
},
"OPC_SP_Temp_Burner5": {
"name": "OPC_SP_Temp_Burner5",
"description": "Burner 5",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 5 Temperature - °C",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 5 Temperature - °C"
},
"OPC_SP_Temp_Burner6": {
"name": "OPC_SP_Temp_Burner6",
"description": "Burner 6",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 6 Temperature - °C",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 6 Temperature - °C"
},
"OPC_SP_Temp_Burner7": {
"name": "OPC_SP_Temp_Burner7",
"description": "Burner 7",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 7 Temperature - °C",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 7 Temperature - °C"
},
"OPC_SP_Temp_Burner8": {
"name": "OPC_SP_Temp_Burner8",
"description": "Burner 8",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 8 Temperature - °C",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 8 Temperature - °C"
},
"OPC_SP_Temp_Burner9": {
"name": "OPC_SP_Temp_Burner9",
"description": "Burner 9",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 9 Temperature - °C",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Temperature\"#Burner 9 Temperature - °C"
},
"OPC_SP_Termoset_ThermoTime": {
"name": "OPC_SP_Termoset_ThermoTime",
"description": "Thermoset Time",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Thermoset\"#Thermoset Time",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Thermoset\"#Thermoset Time"
},
"OPC_SP_Termoset_ThermoTemp": {
"name": "OPC_SP_Termoset_ThermoTemp",
"description": "Thermoset Temperature",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Thermoset\"#Thermoset Temperature",
"tipoMem": "FloatABCD",
"factor": 1
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Thermoset\"#Thermoset Temperature"
},
"ResetCounter": {
"name": "ResetCounter",
"description": "Reset Contapezzi",
"memAddr": "ns=3;s=\"Recipe_Table_DB_RW\".\"Reset partial meter counter\"",
"tipoMem": "Boolean"
}
},
"WatchDog": {
+3 -3
View File
@@ -546,13 +546,13 @@
<None Include="DATA\CONF\L020_Rest.wrong.json" />
<None Include="DATA\CONF\L020.ini" />
<None Include="DATA\CONF\SIMUL_01_WD.ini" />
<None Include="DATA\CONF\Tend_RAMA_100_47.ini">
<None Include="DATA\CONF\Tend_RAMA_10_47.ini">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="DATA\CONF\Tend_RAMA_100_47.json">
<None Include="DATA\CONF\Tend_RAMA_10_47.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="DATA\CONF\Tend_RAMA_100_47_alarm.json">
<None Include="DATA\CONF\Tend_RAMA_10_47_alarm.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="DATA\CONF\VL27.json" />
+11 -1
View File
@@ -2735,7 +2735,17 @@ namespace IOB_WIN_NEXT.IobOpc
// valori "diretti"
if (listWriteReq.Count > 0)
{
UA_ref.WriteNodes(listWriteReq);
var toWrite = new Dictionary<NodeId, IEnumerable<string>>();
foreach (var item in listWriteReq)
{
toWrite.Add(item.NodeId, new List<string>() { $"{item.Value.Value}" });
}
UA_ref.WriteValues(toWrite);
// modalità calssica alternativa?!?
#if false
UA_ref.WriteNodes(listWriteReq);
#endif
}
// se valori Udt con modalità alternativa
if (nodesUdt2Write.Count > 0)
+192
View File
@@ -4,6 +4,7 @@ using Newtonsoft.Json;
using Opc.Ua;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
namespace IOB_WIN_NEXT.IobOpc
@@ -397,5 +398,196 @@ namespace IOB_WIN_NEXT.IobOpc
#endif
#endregion Protected Methods
/// <summary>
/// Effettua vera scrittura parametri
/// </summary>
/// <param name="updatedPar"></param>
protected override void plcWriteParams(ref List<objItem> updatedPar)
{
// solo se connesso!
if (connectionOk)
{
dataConf currMem = null;
int byteSize = 0;
string memAddrWrite = "";
string serObj = "";
if (updatedPar != null)
{
// valori da scrivere in memoria
Dictionary<string, WriteValue> nodes2Write = new Dictionary<string, WriteValue>();
Dictionary<string, Dictionary<string, string>> nodesUdt2Write = new Dictionary<string, Dictionary<string, string>>();
Dictionary<string, string> currUdsDict = new Dictionary<string, string>();
// controllo i parametri... ne gestisco 4...
foreach (var item in updatedPar)
{
if (connectionOk)
{
Opc.Ua.DataValue currNodeVal = new DataValue();
try
{
memAddrWrite = "";
int valInt = 0;
double valReal = 0;
// cerco in area memMapWrite...
if (memMap.mMapWrite.ContainsKey(item.uid))
{
// recupero!
currMem = memMap.mMapWrite[item.uid];
byteSize = currMem.size;
memAddrWrite = currMem.memAddr;
// init obj scrittura
WriteValue commWriteVal = new WriteValue();
commWriteVal.Value = new DataValue();
commWriteVal.AttributeId = Attributes.Value;
// faccio preliminarmente upsertKey...
upsertKey(memAddrWrite, currMem.value);
serObj = JsonConvert.SerializeObject(item);
lgInfo($"Inizio processing plcWriteParams per {currMem.name} | valore richiesto {currMem.value}");
lgInfo($"{Environment.NewLine}---------------UPDATED PARAM:{Environment.NewLine}{serObj}{Environment.NewLine}---------------");
serObj = JsonConvert.SerializeObject(currMem);
lgInfo($"{Environment.NewLine}---------------MEMORY CONTENT:{Environment.NewLine}{serObj}{Environment.NewLine}---------------");
// verifico se devo processare byte[]...
bool isUds = memAddrWrite.Contains(opcUaParams.kvDelim);
if (isUds)
{
// ciclo e calcolo valore
int iPos = memAddrWrite.IndexOf(opcUaParams.kvDelim);
string nodeId = memAddrWrite.Substring(0, iPos);
string varName = memAddrWrite.Substring(iPos + 1);
//cerco se ci sia già un record Uds...
if (nodesUdt2Write.ContainsKey(nodeId))
{
currUdsDict = nodesUdt2Write[nodeId];
// controllo valore...
if (currUdsDict.ContainsKey(varName))
{
currUdsDict[varName] = item.reqValue;
}
else
{
currUdsDict.Add(varName, item.reqValue);
}
nodesUdt2Write[nodeId] = currUdsDict;
}
else
{
currUdsDict = new Dictionary<string, string>();
currUdsDict.Add(varName, item.reqValue);
nodesUdt2Write.Add(nodeId, currUdsDict);
}
}
else
{
// init generico x scrittura nell'oggetto OPC-UA direttamente
commWriteVal.NodeId = new NodeId(memAddrWrite);
commWriteVal.Value.Value = item.reqValue;
// check tipo specifico
switch (currMem.tipoMem)
{
case plcDataType.Boolean:
break;
case plcDataType.Int:
case plcDataType.DInt:
case plcDataType.Word:
case plcDataType.DWord:
int.TryParse(item.reqValue, out valInt);
commWriteVal.Value.Value = valInt;
break;
case plcDataType.Real:
double.TryParse(item.reqValue, out valReal);
commWriteVal.Value.Value = valReal;
break;
case plcDataType.String:
commWriteVal.Value.Value = item.reqValue;
break;
default:
break;
}
}
lgInfo($"---------------{Environment.NewLine}OPC-UA data:{Environment.NewLine}NodeId: {commWriteVal.NodeId}{Environment.NewLine}Value: {commWriteVal.Value.Value}{Environment.NewLine}---------------");
// se supero soglia errori lettura --> disconnetto e resetto
if (numErroriCheck >= maxErroriCheck)
{
lgInfo($"numErroriCheck: {numErroriCheck} --> richiesta disconnessione adapter con tryDisconnect");
numErroriCheck = 0;
tryDisconnect();
}
else
{
if (!string.IsNullOrEmpty(memAddrWrite) && !string.IsNullOrEmpty($"{commWriteVal.NodeId}"))
{
// cerco se ci fosse già --> aggiorno
if (nodes2Write.ContainsKey($"{commWriteVal.NodeId}"))
{
nodes2Write[$"{commWriteVal.NodeId}"] = commWriteVal;
}
else
{
nodes2Write.Add($"{commWriteVal.NodeId}", commWriteVal);
}
// 2023.09.19 resetto richiesta
item.reqValue = "";
}
else
{
lgInfo($"Errore: memAddrWrite vuoto!");
}
}
}
else
{
lgInfo($"Errore uid non trovato in area write memory: {item.uid}, ci sono {memMap.mMapWrite.Count} in area write");
}
}
catch (Exception exc)
{
lgError($"Eccezione in fase di plcWriteParams per item {item.uid} con valore {item.value}{Environment.NewLine}{exc}");
}
}
}
if (connectionOk && (nodes2Write.Count + nodesUdt2Write.Count) > 0)
{
List<WriteValue> listWriteReq = nodes2Write.Select(x => x.Value).ToList();
// valori "diretti"
if (listWriteReq.Count > 0)
{
var toWrite = new Dictionary<NodeId, IEnumerable<string>>();
foreach (var item in listWriteReq)
{
toWrite.Add(item.NodeId, new List<string>() { $"{item.Value.Value}" });
}
// scrittura modalità siemens
UA_ref.WriteValues(toWrite);
}
// se valori Udt con modalità alternativa
if (nodesUdt2Write.Count > 0)
{
foreach (var item in nodesUdt2Write)
{
UA_ref.WriteNodesUdt(item.Key, item.Value);
}
}
}
}
}
}
}
}
+1 -1
View File
@@ -172,7 +172,7 @@ namespace IOB_WIN_NEXT.IobOpc
objItem resetCnt = new objItem()
{
uid = "ResetCounter",
reqValue = "true",
reqValue = "1",
name = "ResetCounter"
};
ListaCalcParams.Add(resetCnt);
+130 -1
View File
@@ -860,6 +860,135 @@ namespace IOB_WIN_NEXT
}
}
/// <summary>
/// Writes values to node Ids
/// </summary>
/// <param name="valuesByNodeId">Mulitple NodeIds with there values (multiple possible if not a scalar).</param>
/// <exception cref="Exception">Throws and forwards any exception with short error description.</exception>
public void WriteValues(Dictionary<NodeId, IEnumerable<string>> valuesByNodeId)
{
//Create a collection of values to write
WriteValueCollection valuesToWrite = new WriteValueCollection();
foreach (var keyValuePair in valuesByNodeId)
{
NodeId nodeId = keyValuePair.Key;
IEnumerable<string> values = keyValuePair.Value;
//Get the OPC UA data type and the Rank
Node node = m_session.ReadNode(nodeId);
VariableNode variableNode = (VariableNode)node.DataLock;
NodeId datatypeId = variableNode.DataType;
BuiltInType targetype = TypeInfo.GetBuiltInType(datatypeId);
//Ensure that target type is not null by reading the node of the data type id
if (targetype == BuiltInType.Null)
{
try
{
//Get the node id of the parent base data type
NodeId tempNodeId = GetParentDataType(datatypeId, m_session);
targetype = TypeInfo.GetBuiltInType(tempNodeId);
if (targetype == BuiltInType.Null)//Ensure that the entered node id is not of type struct
{
throw new Exception("The entered node id may be of type struct. Please use the methods for read/write structs.");
}
}
catch
{
throw new Exception("The node id data type is not castable. Please check the data type.");
}
}
int valueRank = variableNode.ValueRank;
DataValue dataValue = null;
//Check if there is a value entered
if (!values.Any() || nodeId == null) //no value in the textbox
{
throw new Exception("There is no NodeId or value entered.");
}
//Ensure that boolean entries have lower case initial and float, double and long double have the rigth format
List<string> tempValues = new List<string>();
if (targetype == BuiltInType.Boolean)
{
foreach (string tempValue in values)
{
tempValues.Add(tempValue.ToLower());
}
values = tempValues;
}
if (targetype == BuiltInType.Float || targetype == BuiltInType.Double)
{
foreach (string tempValue in values)
{
tempValues.Add(tempValue.Replace(',', '.'));
}
values = tempValues;
}
//Check if the inputed value has the type matrix or array
if (valueRank >= ValueRanks.OneDimension)
{
//Cast values in the target type
Array castValues = TypeInfo.CastArray(values.ToArray(), BuiltInType.Null, targetype, (object source, BuiltInType srcType, BuiltInType dstType) => TypeInfo.Cast(source, dstType));
if (valueRank == ValueRanks.OneDimension) //Check if inputed value is array
{
dataValue = new DataValue(new Variant(castValues, new TypeInfo(targetype, valueRank)));
}
else //Inputed value has more then one dimension
{
//Get matrix dimensions
int[] dimensions = new int[valueRank];
for (int i = 0; i < valueRank; i++)
{
dimensions[i] = (int)variableNode.ArrayDimensions[i];
}
Matrix matrix = new Matrix(castValues, targetype, dimensions);
dataValue = new DataValue(new Variant(matrix));
}
}
else
{
try //OPC UA data type with type scalar
{
dataValue = new DataValue(new Variant(TypeInfo.Cast(values.First(), targetype)));
}
catch //no OPC UA data type
{
throw new FormatException($"The value inputed [{values.First()}] is not convertable to type {targetype}.");
}
}
//Create a WriteValue using the NodeId, dataValue and attributeType
WriteValue valueToWrite = new WriteValue()
{
Value = dataValue,
NodeId = nodeId,
AttributeId = Attributes.Value
};
//Add the dataValues to the collection
valuesToWrite.Add(valueToWrite);
}
StatusCodeCollection result;
//Write the collection to the server
m_session.Write(null, valuesToWrite, out result, out _);
foreach (StatusCode code in result)
{
lgDebug($" {code}");
#if false
if (code != 0)
{
throw new Exception(code.ToString());
}
#endif
}
}
/// <summary>
/// Write a list of nodes to the Server
/// </summary>
@@ -898,7 +1027,7 @@ namespace IOB_WIN_NEXT
foreach (StatusCode writeResult in results)
{
lgDebug(" {writeResult}");
lgDebug($" {writeResult}");
}
}
catch (Exception ex)