Ancora update x adapter OPC UA
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32519.379
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MP.MONO.ADAPTER.OPC", "MP.MONO.ADAPTER.OPC\MP.MONO.ADAPTER.OPC.csproj", "{458FD824-7804-4CF9-8C43-463C1F5659DA}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MP.MONO.ADAPTER.OLD", "MP.MONO.ADAPTER.OLD\MP.MONO.ADAPTER.OLD.csproj", "{84F0ABFE-ADD6-426D-BD9B-E4E9086EE169}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{458FD824-7804-4CF9-8C43-463C1F5659DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{458FD824-7804-4CF9-8C43-463C1F5659DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{458FD824-7804-4CF9-8C43-463C1F5659DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{458FD824-7804-4CF9-8C43-463C1F5659DA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{84F0ABFE-ADD6-426D-BD9B-E4E9086EE169}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{84F0ABFE-ADD6-426D-BD9B-E4E9086EE169}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{84F0ABFE-ADD6-426D-BD9B-E4E9086EE169}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{84F0ABFE-ADD6-426D-BD9B-E4E9086EE169}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3811E8B4-1DD3-4841-9840-1B1A08782CD3}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -5,7 +5,7 @@
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>1.12206.1410</Version>
|
||||
<Version>1.12206.1416</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>MAPO-MONO</i>
|
||||
<h4>Version: 1.12206.1410</h4>
|
||||
<h4>Version: 1.12206.1416</h4>
|
||||
<br /> Release Note:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.12206.1410
|
||||
1.12206.1416
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>1.12206.1410</version>
|
||||
<version>1.12206.1416</version>
|
||||
<url>http://nexus.steamware.net/repository/SWS/MP.MONO.ADAPTER/stable/LAST/MP.Mon.zip</url>
|
||||
<changelog>http://nexus.steamware.net/repository/SWS/MP.MONO.ADAPTER/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
+142
-156
@@ -1,12 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections;
|
||||
using NLog;
|
||||
using Opc.Ua;
|
||||
using Opc.Ua.Client;
|
||||
using NLog;
|
||||
using System.Collections;
|
||||
|
||||
namespace MP.MONO.ADAPTER
|
||||
{
|
||||
@@ -15,20 +10,6 @@ namespace MP.MONO.ADAPTER
|
||||
/// </summary>
|
||||
public class opcUaMonitItemChange : EventArgs
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Monitored Item da notificare
|
||||
/// </summary>
|
||||
private readonly MonitoredItem _monitoredItem;
|
||||
|
||||
/// <summary>
|
||||
/// Valore notifica
|
||||
/// </summary>
|
||||
private readonly MonitoredItemNotification _notification;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
@@ -62,34 +43,27 @@ namespace MP.MONO.ADAPTER
|
||||
}
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// Monitored Item da notificare
|
||||
/// </summary>
|
||||
private readonly MonitoredItem _monitoredItem;
|
||||
|
||||
/// <summary>
|
||||
/// Valore notifica
|
||||
/// </summary>
|
||||
private readonly MonitoredItemNotification _notification;
|
||||
|
||||
#endregion Private Fields
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OPC UA Client with examples of basic functionality.
|
||||
/// </summary>
|
||||
public class UAClient
|
||||
{
|
||||
#region Private Fields
|
||||
|
||||
private readonly string currIob;
|
||||
private readonly Action<IList, IList> m_validateResponse;
|
||||
private ApplicationConfiguration m_configuration;
|
||||
private Session m_session;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
protected static Logger lg;
|
||||
protected static bool isLogVerbose = false;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The user identity to use when creating the session.
|
||||
/// </summary>
|
||||
public IUserIdentity CurrUserIdentity { get; set; } = new UserIdentity();
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
@@ -126,6 +100,11 @@ namespace MP.MONO.ADAPTER
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// The user identity to use when creating the session.
|
||||
/// </summary>
|
||||
public IUserIdentity CurrUserIdentity { get; set; } = new UserIdentity();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the server URL.
|
||||
/// </summary>
|
||||
@@ -138,105 +117,6 @@ namespace MP.MONO.ADAPTER
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Handles the certificate validation event.
|
||||
/// This event is triggered every time an untrusted certificate is received from the server.
|
||||
/// </summary>
|
||||
private void CertificateValidation(CertificateValidator sender, CertificateValidationEventArgs e)
|
||||
{
|
||||
bool certificateAccepted = true;
|
||||
|
||||
// ****
|
||||
// Implement a custom logic to decide if the certificate should be
|
||||
// accepted or not and set certificateAccepted flag accordingly.
|
||||
// The certificate can be retrieved from the e.Certificate field
|
||||
// ***
|
||||
|
||||
ServiceResult error = e.Error;
|
||||
while (error != null)
|
||||
{
|
||||
lgError($"{error.StatusCode} | {error.Code} | {error.LocalizedText}");
|
||||
error = error.InnerResult;
|
||||
}
|
||||
|
||||
if (certificateAccepted)
|
||||
{
|
||||
lgInfo($"Untrusted Certificate accepted. SubjectName = {e.Certificate.SubjectName}");
|
||||
}
|
||||
|
||||
e.AcceptAll = certificateAccepted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle DataChange notifications from Server
|
||||
/// </summary>
|
||||
private void OnMonitoredItemNotification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Log MonitoredItem Notification event
|
||||
MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification;
|
||||
|
||||
// sollevo evento notifica vaziazione MonitoredItem
|
||||
if (eh_MonItChange != null)
|
||||
{
|
||||
eh_MonItChange(this, new opcUaMonitItemChange(monitoredItem, notification));
|
||||
}
|
||||
lgTrace($"Notification Received | Variable: {monitoredItem.DisplayName} | Value: {notification.Value}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lgError($"OnMonitoredItemNotification error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
protected void lgError(string message)
|
||||
{
|
||||
lg.Factory.Configuration.Variables["codIOB"] = currIob;
|
||||
lg.Error(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
protected void lgInfo(string message)
|
||||
{
|
||||
lg.Factory.Configuration.Variables["codIOB"] = currIob;
|
||||
lg.Info(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging DEBUG corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
protected void lgDebug(string message)
|
||||
{
|
||||
lg.Factory.Configuration.Variables["codIOB"] = currIob;
|
||||
lg.Info(message);
|
||||
}
|
||||
/// <summary>
|
||||
/// Effettua logging TRACE corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
protected void lgTrace(string message)
|
||||
{
|
||||
lg.Factory.Configuration.Variables["codIOB"] = currIob;
|
||||
lg.Trace(message);
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
@@ -384,14 +264,11 @@ namespace MP.MONO.ADAPTER
|
||||
|
||||
try
|
||||
{
|
||||
// Define the UA Method to call
|
||||
// Parent node - Objects\CTT\Methods
|
||||
// Method node - Objects\CTT\Methods\Add
|
||||
// Define the UA Method to call Parent node - Objects\CTT\Methods Method node - Objects\CTT\Methods\Add
|
||||
NodeId objectId = new NodeId("ns=2;s=Methods");
|
||||
NodeId methodId = new NodeId("ns=2;s=Methods_Add");
|
||||
|
||||
// Define the method parameters
|
||||
// Input argument requires a Float and an UInt32 value
|
||||
// Define the method parameters Input argument requires a Float and an UInt32 value
|
||||
object[] inputArguments = new object[] { (float)10.5, (uint)10 };
|
||||
IList<object> outputArguments = null;
|
||||
|
||||
@@ -428,8 +305,8 @@ namespace MP.MONO.ADAPTER
|
||||
{
|
||||
lgInfo("Connecting...");
|
||||
|
||||
// Get the endpoint by connecting to server's discovery endpoint.
|
||||
// Try to find the first endopint without security.
|
||||
// Get the endpoint by connecting to server's discovery endpoint. Try to find
|
||||
// the first endopint without security.
|
||||
EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint(ServerUrl, false);
|
||||
|
||||
EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(m_configuration);
|
||||
@@ -572,7 +449,6 @@ namespace MP.MONO.ADAPTER
|
||||
return answ;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Read a SINGLE of nodes value (RAW) from Server
|
||||
/// </summary>
|
||||
@@ -589,7 +465,6 @@ namespace MP.MONO.ADAPTER
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
#region Read the Value attribute of a node by calling the Session.ReadValue method
|
||||
|
||||
try
|
||||
@@ -613,8 +488,6 @@ namespace MP.MONO.ADAPTER
|
||||
return answ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Read a list of nodes from Server
|
||||
/// </summary>
|
||||
@@ -812,8 +685,7 @@ namespace MP.MONO.ADAPTER
|
||||
return monItList;
|
||||
}
|
||||
|
||||
/// Write a list of nodes to the Server
|
||||
/// </summary>
|
||||
/// Write a list of nodes to the Server </summary>
|
||||
public void WriteNodes(List<WriteValue> node2Write)
|
||||
{
|
||||
if (m_session == null || m_session.Connected == false)
|
||||
@@ -1001,5 +873,119 @@ namespace MP.MONO.ADAPTER
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
protected static bool isLogVerbose = false;
|
||||
protected static Logger lg;
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging DEBUG corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
protected void lgDebug(string message)
|
||||
{
|
||||
lg.Factory.Configuration.Variables["codIOB"] = currIob;
|
||||
lg.Info(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
protected void lgError(string message)
|
||||
{
|
||||
lg.Factory.Configuration.Variables["codIOB"] = currIob;
|
||||
lg.Error(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
protected void lgInfo(string message)
|
||||
{
|
||||
lg.Factory.Configuration.Variables["codIOB"] = currIob;
|
||||
lg.Info(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging TRACE corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
protected void lgTrace(string message)
|
||||
{
|
||||
lg.Factory.Configuration.Variables["codIOB"] = currIob;
|
||||
lg.Trace(message);
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private readonly string currIob;
|
||||
private readonly Action<IList, IList> m_validateResponse;
|
||||
private ApplicationConfiguration m_configuration;
|
||||
private Session m_session;
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Handles the certificate validation event. This event is triggered every time an
|
||||
/// untrusted certificate is received from the server.
|
||||
/// </summary>
|
||||
private void CertificateValidation(CertificateValidator sender, CertificateValidationEventArgs e)
|
||||
{
|
||||
bool certificateAccepted = true;
|
||||
|
||||
// **** Implement a custom logic to decide if the certificate should be accepted or not
|
||||
// and set certificateAccepted flag accordingly. The certificate can be retrieved from
|
||||
// the e.Certificate field ***
|
||||
|
||||
ServiceResult error = e.Error;
|
||||
while (error != null)
|
||||
{
|
||||
lgError($"{error.StatusCode} | {error.Code} | {error.LocalizedText}");
|
||||
error = error.InnerResult;
|
||||
}
|
||||
|
||||
if (certificateAccepted)
|
||||
{
|
||||
lgInfo($"Untrusted Certificate accepted. SubjectName = {e.Certificate.SubjectName}");
|
||||
}
|
||||
|
||||
e.AcceptAll = certificateAccepted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle DataChange notifications from Server
|
||||
/// </summary>
|
||||
private void OnMonitoredItemNotification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Log MonitoredItem Notification event
|
||||
MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification;
|
||||
|
||||
// sollevo evento notifica vaziazione MonitoredItem
|
||||
if (eh_MonItChange != null)
|
||||
{
|
||||
eh_MonItChange(this, new opcUaMonitItemChange(monitoredItem, notification));
|
||||
}
|
||||
lgTrace($"Notification Received | Variable: {monitoredItem.DisplayName} | Value: {notification.Value}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lgError($"OnMonitoredItemNotification error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.32510.428
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32519.379
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MP.MONO.ADAPTER.OPC", "MP.MONO.ADAPTER.OPC\MP.MONO.ADAPTER.OPC.csproj", "{458FD824-7804-4CF9-8C43-463C1F5659DA}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MP.MONO.ADAPTER.OPC", "MP.MONO.ADAPTER.OPC\MP.MONO.ADAPTER.OPC.csproj", "{458FD824-7804-4CF9-8C43-463C1F5659DA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
{
|
||||
"BrowseFullVal": "ns=1;s=OSAI-PLC",
|
||||
"BrowseNSIndex": 1,
|
||||
"BrowseValue": 0,
|
||||
"keyPartCount": "1:507_2_WORKPIECE QTY",
|
||||
"keyPartReq": "",
|
||||
"keyPartId": "",
|
||||
"keyProgName": "1:502_1_RECIPE NAME",
|
||||
"keyRunMode": "",
|
||||
"pingAsPowerOn": true,
|
||||
//"Identity": {
|
||||
// "UserName": "CUSTOMER",
|
||||
// "Passwd": "BLM"
|
||||
//},
|
||||
"condWork": [
|
||||
{
|
||||
"keyName": "1:1_1_MACHINE STATUS",
|
||||
"targetValue": "ON"
|
||||
}
|
||||
],
|
||||
"condWorkOpc": {
|
||||
"checkMode": "AND",
|
||||
"checkList": [
|
||||
{
|
||||
"keyName": "MachineStatus(0)",
|
||||
"targetValue": "4"
|
||||
}
|
||||
]
|
||||
},
|
||||
"condPowerOn": {
|
||||
"checkMode": "OR",
|
||||
"negateValue": true,
|
||||
"checkList": [
|
||||
{
|
||||
"keyName": "1:1_1_MACHINE STATUS",
|
||||
"targetValue": "ON"
|
||||
},
|
||||
{
|
||||
"keyName": "1:500_1_STATUS",
|
||||
"targetValue": "CYCLE"
|
||||
},
|
||||
{
|
||||
"keyName": "1:501_1_MODE",
|
||||
"targetValue": "AUTO"
|
||||
}
|
||||
]
|
||||
},
|
||||
"condReady": {
|
||||
"checkMode": "OR",
|
||||
"checkList": [
|
||||
//{
|
||||
// "keyName": "MachineStatus(0)",
|
||||
// "targetValue": "3"
|
||||
//},
|
||||
//{
|
||||
// "keyName": "MachineStatus(0)",
|
||||
// "targetValue": "5"
|
||||
//}
|
||||
]
|
||||
},
|
||||
"condManual": {
|
||||
"checkMode": "AND",
|
||||
"checkList": [
|
||||
//{
|
||||
// "keyName": "MachineStatus(0)",
|
||||
// "targetValue": "8"
|
||||
//}
|
||||
]
|
||||
},
|
||||
"condEStop": {
|
||||
"checkMode": "AND",
|
||||
"checkList": [
|
||||
//{
|
||||
// "keyName": "EmergencyState",
|
||||
// "targetValue": "0"
|
||||
//}
|
||||
]
|
||||
},
|
||||
"condError": {
|
||||
"checkMode": "AND",
|
||||
"checkList": [
|
||||
//{
|
||||
// "keyName": "MachineStatus(0)",
|
||||
// "targetValue": "6"
|
||||
//}
|
||||
]
|
||||
},
|
||||
"condCountEnabled": {
|
||||
"checkMode": "AND",
|
||||
"checkList": []
|
||||
},
|
||||
"condWarmUpCoolDown": {
|
||||
"checkMode": "OR",
|
||||
"negateValue": true,
|
||||
"checkList": []
|
||||
},
|
||||
"condWarning": {
|
||||
"checkMode": "AND",
|
||||
"checkList": [
|
||||
//{
|
||||
// "keyName": "MachineStatus(0)",
|
||||
// "targetValue": "9"
|
||||
//}
|
||||
]
|
||||
},
|
||||
"condSetup": {
|
||||
"checkMode": "AND",
|
||||
"checkList": [
|
||||
//{
|
||||
// "keyName": "MachineStatus(0)",
|
||||
// "targetValue": "7"
|
||||
//}
|
||||
]
|
||||
},
|
||||
"fluxLogVeto": [],
|
||||
"itemTranslation": {
|
||||
"avail": "Machine Available",
|
||||
"rstat": "Execution Mode",
|
||||
"mode": "Controller Mode",
|
||||
"PartName(0)": "Program Name",
|
||||
"PartDone(0)": "Pezzi Prodotti",
|
||||
"PartToDo(0)": "Qta Richiesta",
|
||||
"MachineStatus(0)": "Stato Macchina principale",
|
||||
"MachineStatus(1)": "Stato Macchina secondario",
|
||||
"EmergencyState": "Emergenza",
|
||||
"fdovrd": "PATH FEED OVERRIDE",
|
||||
"rovrd": "PATH RAPID OVERRIDE"
|
||||
},
|
||||
"subscribedItems": [
|
||||
"ns=1;s=1_1_MACHINE STATUS",
|
||||
"ns=1;s=1_2_MACHINE COUNTER OFF",
|
||||
"ns=1;s=2_1_AXES STATUS",
|
||||
"ns=1;s=2_2_AXES COUNTER OFF",
|
||||
"ns=1;s=3_1_ALARM NC",
|
||||
"ns=1;s=3_2_ALARM PLC 1",
|
||||
"ns=1;s=3_3_ALARM PLC 2",
|
||||
"ns=1;s=3_4_ALARM PLC 3",
|
||||
"ns=1;s=3_5_ALARM PLC 4",
|
||||
"ns=1;s=3_6_ALARM PLC 5",
|
||||
"ns=1;s=3_7_ALARM PLC 6",
|
||||
"ns=1;s=3_8_ALARM PLC 7",
|
||||
"ns=1;s=3_9_ALARM PLC 8",
|
||||
"ns=1;s=3_10_ALARM PLC 9",
|
||||
"ns=1;s=3_11_ALARM PLC 10",
|
||||
"ns=1;s=4_1_TOOL 1 CURRENT LIFE PC",
|
||||
"ns=1;s=4_2_TOOL 2 CURRENT LIFE PC",
|
||||
"ns=1;s=4_3_TOOL 3 CURRENT LIFE PC",
|
||||
"ns=1;s=4_4_TOOL 4 CURRENT LIFE PC",
|
||||
"ns=1;s=4_5_TOOL 11 CURRENT LIFE PC",
|
||||
"ns=1;s=4_6_TOOL 12 CURRENT LIFE PC",
|
||||
"ns=1;s=4_7_TOOL 13 CURRENT LIFE PC",
|
||||
"ns=1;s=4_8_TOOL 14 CURRENT LIFE PC",
|
||||
"ns=1;s=4_9_TOOL 21 CURRENT LIFE PC",
|
||||
"ns=1;s=4_10_TOOL 22 CURRENT LIFE PC",
|
||||
"ns=1;s=4_11_TOOL 23 CURRENT LIFE PC",
|
||||
"ns=1;s=4_12_TOOL 24 CURRENT LIFE PC",
|
||||
"ns=1;s=4_13_TOOL 31 CURRENT LIFE PC",
|
||||
"ns=1;s=4_14_TOOL 32 CURRENT LIFE PC",
|
||||
"ns=1;s=4_15_TOOL 33 CURRENT LIFE PC",
|
||||
"ns=1;s=4_16_TOOL 34 CURRENT LIFE PC",
|
||||
"ns=1;s=500_1_STATUS",
|
||||
"ns=1;s=500_2_COUNTER CYCLE",
|
||||
"ns=1;s=500_3_COUNTER HOLDA",
|
||||
"ns=1;s=500_4_COUNTER ERROR",
|
||||
"ns=1;s=500_5_COUNTER PAUSE",
|
||||
"ns=1;s=501_1_MODE",
|
||||
"ns=1;s=502_1_RECIPE NAME",
|
||||
"ns=1;s=502_2_PROGRESS BAR",
|
||||
"ns=1;s=25_AXIS 1 LOAD PC",
|
||||
"ns=1;s=26_AXIS 2 LOAD PC",
|
||||
"ns=1;s=27_AXIS 3 LOAD PC",
|
||||
"ns=1;s=28_AXIS 4 LOAD PC",
|
||||
"ns=1;s=29_AXIS 5 LOAD PC",
|
||||
"ns=1;s=30_AXIS 6 LOAD PC",
|
||||
"ns=1;s=31_AXIS 7 LOAD PC",
|
||||
"ns=1;s=32_AXIS 8 LOAD PC",
|
||||
"ns=1;s=33_AXIS 9 LOAD PC",
|
||||
"ns=1;s=34_AXIS 10 LOAD PC",
|
||||
"ns=1;s=35_AXIS 11 LOAD PC",
|
||||
"ns=1;s=36_AXIS 12 LOAD PC",
|
||||
"ns=1;s=37_AXIS 13 LOAD PC",
|
||||
"ns=1;s=38_AXIS 14 LOAD PC",
|
||||
"ns=1;s=39_AXIS 15 LOAD PC",
|
||||
"ns=1;s=45_P2 AXIS V SW OVT UPPER",
|
||||
"ns=1;s=46_P2 AXIS V SW OVT LOWER",
|
||||
"ns=1;s=47_P2 AXIS V ACTUAL POSITION",
|
||||
"ns=1;s=48_P3 AXIS W SW OVT UPPER",
|
||||
"ns=1;s=49_P3 AXIS W SW OVT LOWER",
|
||||
"ns=1;s=50_P3 AXIS W ACTUAL POSITION",
|
||||
"ns=1;s=504_PROC 1 P.P. ORDER",
|
||||
"ns=1;s=505_PROC 1 P.P. PROCESSING",
|
||||
"ns=1;s=506_PROC 1 P.P. PROCESSING PHASE",
|
||||
"ns=1;s=510_PROC 1 FEED OVERRIDE",
|
||||
"ns=1;s=511_PROC 1 FEED PROGRAMMED",
|
||||
"ns=1;s=512_PROC 1 FEED ACTUAL",
|
||||
"ns=1;s=513_PROC 1 SPEED OVERRIDE",
|
||||
"ns=1;s=514_PROC 1 SPEED PROGRAMMED",
|
||||
"ns=1;s=515_PROC 1 SPEED ACTUAL",
|
||||
"ns=1;s=516_PROC 1 SPINDLE 1 LOAD PC",
|
||||
"ns=1;s=517_PROC 1 SPINDLE 2 LOAD PC",
|
||||
"ns=1;s=518_PROC 1 SPINDLE 3 LOAD PC",
|
||||
"ns=1;s=519_PROC 1 SPINDLE 4 LOAD PC"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,722 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using MP.MONO.Core;
|
||||
using MP.MONO.Core.CONF;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using static MP.MONO.Core.CONF.OpcUaParamConf;
|
||||
using static MP.MONO.Core.Enums;
|
||||
|
||||
namespace MP.MONO.ADAPTER.OPC
|
||||
{
|
||||
public class IobGeneric
|
||||
{
|
||||
#region Public Fields
|
||||
|
||||
/// <summary>
|
||||
/// valore booleano di check se sia stato AVVIATO l'adapter (Running)
|
||||
/// </summary>
|
||||
internal bool adpRunning = false;
|
||||
|
||||
/// <summary>
|
||||
/// Data/ora ultimo avvio adapter
|
||||
/// </summary>
|
||||
internal DateTime dtAvvioAdp = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
/// Data/ora ultimo spegnimento adapter
|
||||
/// </summary>
|
||||
internal DateTime dtStopAdp = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
/// dataOra ultimo log periodico...
|
||||
/// </summary>
|
||||
internal DateTime lastPeriodicLog;
|
||||
|
||||
/// <summary>
|
||||
/// dataOra ultimo PING inviato verso il PLC...
|
||||
/// </summary>
|
||||
internal DateTime lastPING = DateTime.Now.AddHours(-1);
|
||||
/// <summary>
|
||||
/// indica se serva refresh parametri e quindi PLC...
|
||||
/// </summary>
|
||||
internal bool needRefresh = true;
|
||||
|
||||
/// <summary>
|
||||
/// Struttura memoria PLC x lettura/scrittura da JSON file
|
||||
/// </summary>
|
||||
public plcMemMap memMap;
|
||||
|
||||
#endregion Public Fields
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Avvia generico IOB
|
||||
/// </summary>
|
||||
/// <param name="confPath"></param>
|
||||
/// <param name="config"></param>
|
||||
public IobGeneric(string confPath, IConfigurationRoot? config)
|
||||
{
|
||||
lg = LogManager.GetCurrentClassLogger();
|
||||
connectionOk = false;
|
||||
configPath = confPath;
|
||||
confMan = config;
|
||||
if (confMan != null)
|
||||
{
|
||||
var selection = confMan.GetSection("Endpoint");
|
||||
if (selection.Exists())
|
||||
{
|
||||
// recupero dati endpoint
|
||||
cIobConf = selection.Get<EndpointData>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Salva verifica stato connessione OK
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal virtual bool connectionOk
|
||||
{
|
||||
get
|
||||
{
|
||||
return _connOk;
|
||||
}
|
||||
set
|
||||
{
|
||||
_connOk = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato
|
||||
/// dtEve#flusso#valore#cont <paramref name="flusso">Flusso dati</paramref><paramref
|
||||
/// name="valore">Valore da salvare</paramref>
|
||||
/// </summary>
|
||||
public string qEncodeFLog(string flusso, string valore)
|
||||
{
|
||||
string answ = "";
|
||||
// fixme todo !!! fare
|
||||
// tenere? cambiare? modificare? si dovrebbe cambiare con invio su channel REDIS dei dati ricevuti, eventualmente divisi x canale secondo setup
|
||||
#if false
|
||||
try
|
||||
{
|
||||
answ = $"{DateTime.Now:yyyyMMddHHmmssfff}#{flusso}#{valore}#{counterULog}";
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
#endif
|
||||
return answ;
|
||||
}
|
||||
/// <summary>
|
||||
/// Accumula in coda i valori Flux Log e logga...
|
||||
/// </summary>
|
||||
/// <param name="val">VALORE RAW (x display)</param>
|
||||
/// <param name="encodedVal">VALORE già processato con qEncodeFLog(...)</param>
|
||||
public void accodaFLog(string val, string encodedVal)
|
||||
{
|
||||
// fixme todo !!! fare
|
||||
// tenere? cambiare? modificare? si dovrebbe cambiare con invio su channel REDIS dei dati ricevuti, eventualmente divisi x canale secondo setup
|
||||
#if false
|
||||
// mostro dati variati letti...
|
||||
displayOtherData(val);
|
||||
// --> accodo (valore già formattato)!
|
||||
QueueFLog.Enqueue(encodedVal);
|
||||
// se abilitato controllo coda FLog (superiore a 0...)
|
||||
if (maxQueueFLog > 0)
|
||||
{
|
||||
// se ho una coda superiore a max ammesso
|
||||
if (QueueFLog.Count > maxQueueFLog)
|
||||
{
|
||||
// elimino valori iniziali fino a tornare al max ammesso...
|
||||
while (QueueFLog.Count > maxQueueFLog)
|
||||
{
|
||||
string currVal = "";
|
||||
QueueFLog.TryDequeue(out currVal);
|
||||
lgInfo($"Eliminazione da coda FLog per superamento maxLengh: {currVal}");
|
||||
}
|
||||
}
|
||||
}
|
||||
// loggo!
|
||||
lgTrace(string.Format("[QUEUE-FLOG] {0}", encodedVal));
|
||||
counterFLog++;
|
||||
if (counterFLog > 9999)
|
||||
{
|
||||
counterFLog = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// indica se ping disabilitato da optPar
|
||||
/// </summary>
|
||||
public bool pingDisabled
|
||||
{
|
||||
get => getCRB("NO_PING");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifica SE si debba fare log verboso (verboso + ogni tot letture IN)
|
||||
/// </summary>
|
||||
public bool verboseLog
|
||||
{
|
||||
get
|
||||
{
|
||||
bool answ = false;
|
||||
int logEvery = getCRI("logEvery");
|
||||
if (logEvery < 1)
|
||||
{
|
||||
logEvery = 10;
|
||||
}
|
||||
|
||||
answ = getCRB("verbose") && (nReadIN % logEvery == 0);
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Properties
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Esecuzione dei task richiesti e pulizia coda richieste eseguite
|
||||
/// </summary>
|
||||
/// <param name="task2exe"></param>
|
||||
public virtual Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
|
||||
{
|
||||
// Verificare il protocollo: dovrebbe togliere SOLO i task eseguiti...
|
||||
Dictionary<string, string> taskDone = new Dictionary<string, string>();
|
||||
if (task2exe != null)
|
||||
{
|
||||
// controllo se memMap != null...
|
||||
if (memMap != null)
|
||||
{
|
||||
bool taskOk = false;
|
||||
string taskVal = "";
|
||||
// cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4
|
||||
foreach (var item in task2exe)
|
||||
{
|
||||
taskOk = false;
|
||||
taskVal = "";
|
||||
// converto richiesta in enum...
|
||||
taskType tName = taskType.nihil;
|
||||
Enum.TryParse(item.Key, out tName);
|
||||
// controllo sulla KEY...
|
||||
switch (tName)
|
||||
{
|
||||
case taskType.setArt:
|
||||
case taskType.setComm:
|
||||
case taskType.setProg:
|
||||
case taskType.setPzComm:
|
||||
// recupero dati da memMap...
|
||||
if (memMap != null && memMap.mMapWrite != null)
|
||||
{
|
||||
if (memMap.mMapWrite.ContainsKey(item.Key))
|
||||
{
|
||||
dataConf currMem = memMap.mMapWrite[item.Key];
|
||||
string addr = currMem.memAddr;
|
||||
taskVal = $"SET task: {item.Key} --> {item.Value} | mem: {currMem.memAddr} - {currMem.size} byte";
|
||||
// salvo il nuovo valore nella memoria... così prox invio lo trasmetterà
|
||||
memMap.mMapWrite[item.Key].value = item.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
taskVal = $"NO DATA MEM, SET task: {item.Key} --> {item.Value}";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
taskVal = $"NO MemMap found, SET task: {item.Key} --> {item.Value}";
|
||||
}
|
||||
// salvo in currProd..
|
||||
saveProdData(new KeyValuePair<string, string>(item.Key, item.Value));
|
||||
|
||||
break;
|
||||
|
||||
case taskType.forceResetPzCount:
|
||||
// reset contapezzi inizio setup
|
||||
taskOk = resetcontapezziPLC();
|
||||
taskVal = taskOk ? "RESET PZ COUNT OK" : "PZ RESET DISABLED | NO EXEC";
|
||||
lgInfo($"Chiamata forceResetPzCount: taskOk: {taskOk} | taskVal: {taskVal}");
|
||||
break;
|
||||
|
||||
case taskType.startSetup:
|
||||
// reset contapezzi inizio setup
|
||||
taskOk = resetcontapezziPLC();
|
||||
taskVal = taskOk ? "RESET: SETUP START" : "PZ RESET DISABLED | NO EXEC";
|
||||
lgInfo($"Chiamata startSetup: taskOk: {taskOk} | taskVal: {taskVal}");
|
||||
break;
|
||||
|
||||
case taskType.stopSetup:
|
||||
// reset contapezzi fine setup SE ESPLICITAMENTE IMPOSTATO
|
||||
if (getCRB("ENABLE_PZ_RESET_stopSetup"))
|
||||
{
|
||||
taskOk = resetcontapezziPLC();
|
||||
}
|
||||
taskVal = taskOk ? "RESET: SETUP END" : "PZ RESET DISABLED | NO EXEC";
|
||||
lgInfo($"Chiamata stopSetup: taskOk: {taskOk} | taskVal: {taskVal}");
|
||||
break;
|
||||
|
||||
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>
|
||||
/// Metodo generico di reset contapezzi...
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public virtual bool resetcontapezziPLC()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Salva valori indicati in prod data
|
||||
/// </summary>
|
||||
/// <param name="item">Item KVP di cui salvare i dati in currProdData come chiave/valore</param>
|
||||
/// <returns></returns>
|
||||
public void saveProdData(KeyValuePair<string, string> item)
|
||||
{
|
||||
// imposto i valori...
|
||||
if (currProdData.ContainsKey(item.Key))
|
||||
{
|
||||
currProdData[item.Key] = item.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
currProdData.Add(item.Key, item.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Metodo base connessione...
|
||||
/// </summary>
|
||||
public virtual void tryConnect()
|
||||
{
|
||||
dtAvvioAdp = DateTime.Now;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Internal Properties
|
||||
|
||||
/// <summary>
|
||||
/// COnfiguraizone Endpoint corrente
|
||||
/// </summary>
|
||||
internal EndpointData cIobConf { get; set; } = new EndpointData();
|
||||
|
||||
internal string configPath { get; set; } = "";
|
||||
|
||||
internal IConfigurationRoot? confMan { get; set; } = null!;
|
||||
|
||||
#endregion Internal Properties
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
internal bool getCRB(string keyName)
|
||||
{
|
||||
bool answ = false;
|
||||
answ = confMan.GetValue<bool>(keyName);
|
||||
return answ;
|
||||
}
|
||||
|
||||
internal int getCRI(string keyName)
|
||||
{
|
||||
int answ = -1;
|
||||
answ = confMan.GetValue<int>(keyName);
|
||||
return answ;
|
||||
}
|
||||
|
||||
internal string getCRS(string keyName)
|
||||
{
|
||||
string answ = "";
|
||||
answ = confMan.GetValue<string>(keyName);
|
||||
return answ;
|
||||
}
|
||||
|
||||
#endregion Internal Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
/// <summary>
|
||||
/// wrapper di log
|
||||
/// </summary>
|
||||
protected static Logger lg;
|
||||
|
||||
protected bool _connOk = false;
|
||||
|
||||
/// <summary>
|
||||
/// Dizionario valori impostati x produzione
|
||||
/// </summary>
|
||||
protected Dictionary<string, string> currProdData = new Dictionary<string, string>();
|
||||
|
||||
/// <summary>
|
||||
/// Dizionario ultimi valori (double) delle TSVC
|
||||
/// </summary>
|
||||
protected Dictionary<string, double> LastTSVC = new Dictionary<string, double>();
|
||||
|
||||
/// <summary>
|
||||
/// Dizionario di VC da trattare come TimeSeries (con conf decodificata + processing successivo...)
|
||||
/// </summary>
|
||||
protected Dictionary<string, VCData> TSVC_Data = new Dictionary<string, VCData>();
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
/// <summary>
|
||||
/// Numero letture IN da avvio
|
||||
/// </summary>
|
||||
protected int nReadIN { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// test ping all'indirizzo PLC/CNC impostato nei parametri
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected IPStatus testPingMachine
|
||||
{
|
||||
get
|
||||
{
|
||||
IPStatus answ = IPStatus.Unknown;
|
||||
// se disabilitato salto...
|
||||
if (pingDisabled)
|
||||
{
|
||||
answ = IPStatus.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
IPAddress address;
|
||||
PingReply reply;
|
||||
using (Ping pingSender = new Ping())
|
||||
{
|
||||
address = IPAddress.Loopback;
|
||||
int pingMsTimeout = cIobConf.PingMsTimeout;
|
||||
IPAddress.TryParse(cIobConf.IpAddress, out address);
|
||||
try
|
||||
{
|
||||
// se != null --> uso address...
|
||||
if (address != null)
|
||||
{
|
||||
reply = pingSender.Send(address, pingMsTimeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
reply = pingSender.Send(cIobConf.IpAddress, pingMsTimeout);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
reply = pingSender.Send(IPAddress.Loopback, pingMsTimeout);
|
||||
}
|
||||
answ = reply.Status;
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Stringa raw dei parametri da scrivere...
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected string getParams2write()
|
||||
{
|
||||
string answ = "";
|
||||
// recuperare da una apposita area REDIS...
|
||||
#if false
|
||||
string url2call = $"{urlGetParams2Write}";
|
||||
if (verboseLog)
|
||||
{
|
||||
lgInfo("chiamata URL " + url2call);
|
||||
}
|
||||
answ = utils.callUrlNow(url2call);
|
||||
// se vuoto faccio seconda prova...
|
||||
if (string.IsNullOrEmpty(answ))
|
||||
{
|
||||
answ = utils.callUrlNow(url2call);
|
||||
}
|
||||
#endif
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging DEBUG corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
protected void lgDebug(string message)
|
||||
{
|
||||
lg.Debug(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging DEBUG corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="args"></param>
|
||||
protected void lgDebug(string message, params object[] args)
|
||||
{
|
||||
lg.Debug(message, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
protected void lgError(string message)
|
||||
{
|
||||
lg.Error(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="args"></param>
|
||||
protected void lgError(string message, params object[] args)
|
||||
{
|
||||
lg.Error(message, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="exception"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="args"></param>
|
||||
protected void lgError(Exception exception, string message, params object[] args)
|
||||
{
|
||||
lg.Error(exception, message, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
protected void lgFatal(string message)
|
||||
{
|
||||
lg.Fatal(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="args"></param>
|
||||
protected void lgFatal(string message, params object[] args)
|
||||
{
|
||||
lg.Fatal(message, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="exception"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="args"></param>
|
||||
protected void lgFatal(Exception exception, string message, params object[] args)
|
||||
{
|
||||
lg.Fatal(exception, message, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
protected void lgInfo(string message)
|
||||
{
|
||||
lg.Info(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="args"></param>
|
||||
protected void lgInfo(string message, params object[] args)
|
||||
{
|
||||
lg.Info(message, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
protected void lgTrace(string message)
|
||||
{
|
||||
lg.Trace(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="args"></param>
|
||||
protected void lgTrace(string message, params object[] args)
|
||||
{
|
||||
lg.Trace(message, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Metodo da overridare x scrivere DAVVERO i parametri sul PLC
|
||||
/// </summary>
|
||||
/// <param name="updatedPar"></param>
|
||||
protected virtual void plcWriteParams(ref List<objItem> updatedPar)
|
||||
{
|
||||
// non faccio nulla di base...
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processa le richieste di scrittura memoria
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected string processMemWriteRequests()
|
||||
{
|
||||
string answ = "";
|
||||
// li salvo nei parametri in memoria locale (ogni adapter DOVREBBE salvare POI sul VERO PLC)
|
||||
List<objItem> writeList = new List<objItem>();
|
||||
List<objItem> updatedPar = new List<objItem>();
|
||||
// recupero elenco delle cose da fare
|
||||
string resp = getParams2write();
|
||||
if (!string.IsNullOrEmpty(resp))
|
||||
{
|
||||
try
|
||||
{
|
||||
writeList = JsonConvert.DeserializeObject<List<objItem>>(resp);
|
||||
// se ho da fare chiamo esecuzione..
|
||||
if (writeList.Count > 0)
|
||||
{
|
||||
foreach (var item in writeList)
|
||||
{
|
||||
// scrivo in memoria
|
||||
if (memMap.mMapWrite.ContainsKey(item.uid))
|
||||
{
|
||||
memMap.mMapWrite[item.uid].value = item.reqValue;
|
||||
// accodo in stringa taskVal...
|
||||
answ += $" | Parameter {item.uid} --> {item.reqValue}";
|
||||
// sistemo valori
|
||||
item.value = item.reqValue;
|
||||
lgInfo($"Richiesta update parametro {item.uid} | actVal = {item.value} | reqVal = {item.reqValue}");
|
||||
item.reqValue = "";
|
||||
// salvo in lista da ritrasmettere
|
||||
updatedPar.Add(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
answ += $" | Error: parameter {item.uid} not found";
|
||||
}
|
||||
}
|
||||
// richiamo scrittura parametri su PLC
|
||||
plcWriteParams(ref updatedPar);
|
||||
// invio su cloud parametri!
|
||||
string rawData = JsonConvert.SerializeObject(updatedPar);
|
||||
lgInfo("Notifica a server scrittura parametri");
|
||||
#if false
|
||||
utils.callUrl($"{urlUpdateWriteParams}", rawData);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError($"Eccezione in processMemWriteRequests:{Environment.NewLine}{exc}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lgError("Non è stata ricevuta risposta x task da eseguire");
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// setup parametri da file di conf
|
||||
/// </summary>
|
||||
protected void setupMemMap()
|
||||
{
|
||||
lgInfo($"setupMemMap | trovati {memMap.mMapRead.Count} parametri Read (TSVC)");
|
||||
lgInfo($"setupMemMap | trovati {memMap.mMapWrite.Count} parametri Write");
|
||||
if (getCRB("verbose"))
|
||||
{
|
||||
string rawMemConf = JsonConvert.SerializeObject(memMap, Formatting.Indented);
|
||||
lgDebug($"setupMemMap | configurazione memoria R/W:{Environment.NewLine}{rawMemConf}");
|
||||
}
|
||||
// se ho variabili read --> genero dati TSVC...
|
||||
if (memMap.mMapRead.Count > 0)
|
||||
{
|
||||
TSVC_Data.Clear();
|
||||
LastTSVC.Clear();
|
||||
VCData currConf;
|
||||
int periodo = 0;
|
||||
VC_func funz = VC_func.POINT;
|
||||
// accodo nella conf...
|
||||
foreach (var item in memMap.mMapRead)
|
||||
{
|
||||
funz = item.Value.func;
|
||||
periodo = item.Value.period;
|
||||
currConf = new VCData()
|
||||
{
|
||||
Funzione = funz,
|
||||
Period = periodo,
|
||||
DTStart = DateTime.Now.AddHours(-1),
|
||||
dataArray = new List<double>()
|
||||
};
|
||||
TSVC_Data.Add(item.Key, currConf);
|
||||
}
|
||||
// documento...
|
||||
foreach (var item in TSVC_Data)
|
||||
{
|
||||
lgTrace($"TSVC: {item.Key} | periodo: {item.Value.Period} | funz: {item.Value.Funzione}");
|
||||
// salvo i valori PREC...
|
||||
LastTSVC.Add(item.Key, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,13 +7,23 @@
|
||||
<PackageId>MP.MONO.ADAPTER.OPC</PackageId>
|
||||
<Company>EgalWare</Company>
|
||||
<Description>OPC UA Console Client</Description>
|
||||
<Copyright>Copyright © 2020+ EgalWare</Copyright>
|
||||
<Copyright>Copyright � 2020+ EgalWare</Copyright>
|
||||
<RootNamespace>MP.MONO.ADAPTER.OPC</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="UAClient.old.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
<PackageReference Include="Mono.Options" Version="6.12.0.148" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Client" Version="1.4.368.58" />
|
||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Configuration" Version="1.4.368.58" />
|
||||
<PackageReference Include="OPCFoundation.NetStandard.Opc.Ua.Core" Version="1.4.368.58" />
|
||||
@@ -24,9 +34,20 @@
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="StackExchange.Redis" Version="2.5.61" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\MP.MONO.Core\MP.MONO.Core.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Quickstarts.ReferenceClient.Config.xml">
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="CONF\MpMonoAdapterClient.Config.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="CONF\Multiax.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MP.MONO.ADAPTER.OPC
|
||||
{
|
||||
/// <summary>
|
||||
/// Classe di estensione x oggetti DataItems OPC-UA con struttura e valori
|
||||
/// </summary>
|
||||
public class OpcUaDataItemExt : Opc.Ua.Client.MonitoredItem
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public OpcUaDataItemExt(Opc.Ua.Client.MonitoredItem MonIt)
|
||||
{
|
||||
if (MonIt != null)
|
||||
{
|
||||
AttributeId = MonIt.AttributeId;
|
||||
CacheQueueSize = MonIt.CacheQueueSize;
|
||||
Handle = MonIt.Handle;
|
||||
DiscardOldest = MonIt.DiscardOldest;
|
||||
DisplayName = MonIt.DisplayName;
|
||||
Encoding = MonIt.Encoding;
|
||||
Filter = MonIt.Filter;
|
||||
IndexRange = MonIt.IndexRange;
|
||||
MonitoringMode = MonIt.MonitoringMode;
|
||||
NodeClass = MonIt.NodeClass;
|
||||
QueueSize = MonIt.QueueSize;
|
||||
RelativePath = MonIt.RelativePath;
|
||||
SamplingInterval = MonIt.SamplingInterval;
|
||||
StartNodeId = MonIt.StartNodeId;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// NodeId univoco dell'oggetto x subscription (StartNodeId)
|
||||
/// </summary>
|
||||
public string nodeId { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Valore (in sec) del periodo di downsampling (0 --> NON usato)
|
||||
/// </summary>
|
||||
public int samplePeriod { get; set; } = 60;
|
||||
|
||||
/// <summary>
|
||||
/// Valore soglia DeadBand (0 --> non usata)
|
||||
/// </summary>
|
||||
public double thresholdDeadBand { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// UUID univoco dell'oggetto --> flusso (DisplayName)
|
||||
/// </summary>
|
||||
public string uid { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Valore Registrato in formato stringa
|
||||
/// </summary>
|
||||
public string value { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// Valore Registrato in formato byte array
|
||||
/// </summary>
|
||||
public byte[] rawByte { get; set; } = new byte[1];
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp data-ora evento registrato
|
||||
/// </summary>
|
||||
public DateTime valueTimestamp { get; set; } = DateTime.Now;
|
||||
|
||||
#endregion Public Properties
|
||||
}
|
||||
}
|
||||
+282
-35
@@ -1,32 +1,3 @@
|
||||
/* ========================================================================
|
||||
* Copyright (c) 2005-2021 The OPC Foundation, Inc. All rights reserved.
|
||||
*
|
||||
* OPC Foundation MIT License 1.00
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The complete license agreement can be found here:
|
||||
* http://opcfoundation.org/License/MIT/1.00/
|
||||
* ======================================================================*/
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
@@ -35,6 +6,15 @@ using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Opc.Ua;
|
||||
using Opc.Ua.Configuration;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using MP.MONO.ADAPTER;
|
||||
using MP.MONO.Core;
|
||||
using MP.MONO.Core.CONF;
|
||||
using MP.MONO.Core.DTO;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using StackExchange.Redis;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MP.MONO.ADAPTER.OPC
|
||||
{
|
||||
@@ -43,22 +23,85 @@ namespace MP.MONO.ADAPTER.OPC
|
||||
/// </summary>
|
||||
public static class Program
|
||||
{
|
||||
private static string redisConf = "";
|
||||
private static string confPath = "";
|
||||
private static string lineSep = "---------------------------------------------";
|
||||
private static Logger Log = LogManager.GetCurrentClassLogger();
|
||||
private static bool verboseLog = false;
|
||||
private static bool logWriting = false;
|
||||
|
||||
/// <summary>
|
||||
/// Redis channel manager
|
||||
/// </summary>
|
||||
private static ISubscriber sub { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Redis DB
|
||||
/// </summary>
|
||||
private static IDatabase? redisDb { get; set; }
|
||||
|
||||
private static Dictionary<string, int> LogSimulator = new Dictionary<string, int>();
|
||||
private static Dictionary<string, DateTime> LastSend = new Dictionary<string, DateTime>();
|
||||
private static DateTime lastLog = DateTime.Now.AddMinutes(-1);
|
||||
|
||||
/// <summary>
|
||||
/// Main entry point.
|
||||
/// </summary>
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
TextWriter output = Console.Out;
|
||||
output.WriteLine("OPC UA Console Reference Client");
|
||||
output.WriteLine("Egalware | MP.MONO.ADAPTER | OPC UA Console Client");
|
||||
|
||||
output.WriteLine("OPC UA library: {0} @ {1} -- {2}",
|
||||
Utils.GetAssemblyBuildNumber(),
|
||||
Utils.GetAssemblyTimestamp().ToString("G", CultureInfo.InvariantCulture),
|
||||
Utils.GetAssemblySoftwareVersion());
|
||||
|
||||
|
||||
// init parte config, vedere https://blog.hildenco.com/2020/05/configuration-in-net-core-console.html
|
||||
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
|
||||
var builder = new ConfigurationBuilder()
|
||||
.AddJsonFile($"appsettings.json", true, true)
|
||||
.AddJsonFile($"appsettings.{env}.json", true, true)
|
||||
.AddEnvironmentVariables();
|
||||
var config = builder.Build();
|
||||
|
||||
// imposto variabili di base
|
||||
redisConf = config.GetConnectionString("Redis");
|
||||
confPath = Path.Combine(Directory.GetCurrentDirectory(), "conf");
|
||||
Random rand = new Random();
|
||||
List<MachineStatus>? statusList = new List<MachineStatus>();
|
||||
List<MachineMode>? modeList = new List<MachineMode>();
|
||||
|
||||
// fix numero minimo dei thread pool x evitare collasso chiamate redis
|
||||
ThreadPool.SetMinThreads(10, 10);
|
||||
|
||||
|
||||
|
||||
logInfo(lineSep, true, true);
|
||||
logInfo($"Starting Machine ADAPTER", true, true);
|
||||
logInfo($"Redis server param: {redisConf.Substring(0, 20)}...", false, true);
|
||||
logInfo(lineSep, true, true);
|
||||
logInfo("", true, true);
|
||||
|
||||
// Setup REDIS
|
||||
ConnectionMultiplexer.SetFeatureFlag("preventthreadtheft", true);
|
||||
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(redisConf);
|
||||
sub = redis.GetSubscriber();
|
||||
redisDb = redis.GetDatabase();
|
||||
|
||||
// salvo configurazioni in redis
|
||||
setupConf();
|
||||
|
||||
// avvio il vero e proprio programma di comunicaizone OPC-UA
|
||||
var currIob = new IobOpcUa(confPath, config);
|
||||
|
||||
logInfo($"Started IOB at path {confPath}", true, true);
|
||||
|
||||
#if false
|
||||
// The application name and config file names
|
||||
var applicationName = "ConsoleReferenceClient";
|
||||
var configSectionName = "Quickstarts.ReferenceClient";
|
||||
var applicationName = "MP.MONO.ADAPTER.OPC";
|
||||
var configSectionName = "MpMonoAdapterOpc";
|
||||
var usage = $"Usage: dotnet {applicationName}.dll [OPTIONS]";
|
||||
|
||||
// command line options
|
||||
@@ -102,7 +145,8 @@ namespace MP.MONO.ADAPTER.OPC
|
||||
// Define the UA Client application
|
||||
ApplicationInstance.MessageDlg = new ApplicationMessageDlg(output);
|
||||
CertificatePasswordProvider PasswordProvider = new CertificatePasswordProvider(password);
|
||||
ApplicationInstance application = new ApplicationInstance {
|
||||
ApplicationInstance application = new ApplicationInstance
|
||||
{
|
||||
ApplicationName = applicationName,
|
||||
ApplicationType = ApplicationType.Client,
|
||||
ConfigSectionName = configSectionName,
|
||||
@@ -113,7 +157,7 @@ namespace MP.MONO.ADAPTER.OPC
|
||||
var config = await application.LoadApplicationConfiguration(silent: false);
|
||||
|
||||
// setup the logging
|
||||
ConsoleUtils.ConfigureLogging(config, applicationName, logConsole, LogLevel.Information);
|
||||
ConsoleUtils.ConfigureLogging(config, applicationName, logConsole, Microsoft.Extensions.Logging.LogLevel.Information);
|
||||
|
||||
// delete old certificate
|
||||
if (renewCertificate)
|
||||
@@ -147,7 +191,8 @@ namespace MP.MONO.ADAPTER.OPC
|
||||
}
|
||||
|
||||
// create the UA Client object and connect to configured server.
|
||||
UAClient uaClient = new UAClient(application.ApplicationConfiguration, output, ClientBase.ValidateResponse) {
|
||||
UAClient uaClient = new UAClient(application.ApplicationConfiguration, output, ClientBase.ValidateResponse)
|
||||
{
|
||||
AutoAccept = autoAccept
|
||||
};
|
||||
|
||||
@@ -180,6 +225,208 @@ namespace MP.MONO.ADAPTER.OPC
|
||||
catch (Exception ex)
|
||||
{
|
||||
output.WriteLine(ex.Message);
|
||||
}
|
||||
#endif
|
||||
|
||||
logInfo("Running - press CTRL-C to stop ADAPTER", false, true);
|
||||
logInfo("", false, true);
|
||||
// Ciclo infinito x attesa chiusura con CTRL-C
|
||||
do
|
||||
{
|
||||
// se non fosse connesso... riprovo la connessione...
|
||||
if (!currIob.connectionOk)
|
||||
{
|
||||
currIob.tryConnect();
|
||||
}
|
||||
// attesa...
|
||||
Thread.Sleep(100);
|
||||
} while (true);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// verifica esistenza file oppure lo crea...
|
||||
/// </summary>
|
||||
private static void checkFilePresent(string filePath)
|
||||
{
|
||||
// verific presenza file log...
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
File.WriteAllText(filePath, $"{filePath} created!");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Setup e salvataggio redis delle conf (es modi/stati)
|
||||
/// </summary>
|
||||
private static void setupConf()
|
||||
{
|
||||
#if false
|
||||
// leggo e salvo conf stati
|
||||
string fullPath = Path.Combine(confPath, "StatusList.json");
|
||||
if (File.Exists(fullPath))
|
||||
{
|
||||
var rawData = File.ReadAllText(fullPath);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
List<MachineStatus>? statusList = JsonConvert.DeserializeObject<List<MachineStatus>>(rawData);
|
||||
// salvo in redis!
|
||||
redisDb.StringSetAsync(Constants.STATUS_CONF_KEY, JsonConvert.SerializeObject(statusList));
|
||||
}
|
||||
}
|
||||
|
||||
// leggo e salvo conf modi
|
||||
fullPath = Path.Combine(confPath, "ModeList.json");
|
||||
if (File.Exists(fullPath))
|
||||
{
|
||||
var rawData = File.ReadAllText(fullPath);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
var localObj = JsonConvert.DeserializeObject<List<MachineMode>>(rawData);
|
||||
// salvo in redis!
|
||||
redisDb.StringSetAsync(Constants.MODE_CONF_KEY, JsonConvert.SerializeObject(localObj));
|
||||
}
|
||||
}
|
||||
|
||||
// leggo e salvo conf allarmi
|
||||
fullPath = Path.Combine(confPath, "AlarmList.json");
|
||||
if (File.Exists(fullPath))
|
||||
{
|
||||
var rawData = File.ReadAllText(fullPath);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
var localObj = JsonConvert.DeserializeObject<List<BaseAlarmConf>>(rawData);
|
||||
if (localObj != null)
|
||||
{
|
||||
// sistemo allarmi
|
||||
foreach (var item in localObj)
|
||||
{
|
||||
item.setupData();
|
||||
// loggo
|
||||
logInfo($"Decodifica aree alarmMap: {item.description} | {item.memAddr} x {item.size} byte | {item.messages.Count} messaggi allarme", true, true);
|
||||
}
|
||||
}
|
||||
// salvo in redis!
|
||||
redisDb.StringSetAsync(Constants.ALARMS_CONF_KEY, JsonConvert.SerializeObject(localObj));
|
||||
}
|
||||
}
|
||||
|
||||
// leggo e salvo conf parametri
|
||||
fullPath = Path.Combine(confPath, "ParamList.json");
|
||||
if (File.Exists(fullPath))
|
||||
{
|
||||
var rawData = File.ReadAllText(fullPath);
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
var localObj = JsonConvert.DeserializeObject<List<DisplayDataDTO>>(rawData);
|
||||
// salvo in redis!
|
||||
redisDb.StringSetAsync(Constants.PARAMS_CONF_KEY, JsonConvert.SerializeObject(localObj));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ConfigManager configManager = new ConfigManager(redisConf, confPath);
|
||||
_ = configManager.getAlarmsConf();
|
||||
_ = configManager.getMachineModeConf();
|
||||
_ = configManager.getMachineStatusConf();
|
||||
_ = configManager.getParamsConf();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua log INFO su file e se richiesto su console
|
||||
/// </summary>
|
||||
private static void logInfo(string msg, bool log2file = true, bool log2console = false)
|
||||
{
|
||||
if (log2console)
|
||||
{
|
||||
Console.WriteLine(msg);
|
||||
}
|
||||
if (log2file)
|
||||
{
|
||||
Log.Info(msg);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Effettua log ERROR su file e se richiesto su console
|
||||
/// </summary>
|
||||
private static void logError(string msg, bool log2file = true, bool log2console = false)
|
||||
{
|
||||
if (log2console)
|
||||
{
|
||||
Console.WriteLine(msg);
|
||||
}
|
||||
if (log2file)
|
||||
{
|
||||
Log.Error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private static void saveAndSendMessage(string memKey, string value, string notifyChannel, string message)
|
||||
{
|
||||
// effettuo la scrittura nell'area di memoria indicata SE passato intervallo minimo
|
||||
bool doSend = true;
|
||||
if (LastSend.ContainsKey(memKey))
|
||||
{
|
||||
if (DateTime.Now.Subtract(LastSend[memKey]).TotalSeconds < 60)
|
||||
{
|
||||
doSend = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LastSend.Add(memKey, DateTime.Now);
|
||||
}
|
||||
if (doSend)
|
||||
{
|
||||
redisDb.StringSetAsync(memKey, value);
|
||||
LastSend[memKey] = DateTime.Now;
|
||||
logInfo($"Redis Cache Key: {memKey}");
|
||||
}
|
||||
//redisDb.SetAdd(memKey, value);
|
||||
|
||||
// invio notifica tramite il canale richiesto
|
||||
sub.Publish(notifyChannel, message);
|
||||
if (verboseLog)
|
||||
{
|
||||
logInfo($"[{notifyChannel}] key: {memKey} | val: {value} | message: {message}");
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!logWriting)
|
||||
{
|
||||
if (LogSimulator.ContainsKey(notifyChannel))
|
||||
{
|
||||
LogSimulator[notifyChannel]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogSimulator.Add(notifyChannel, 1);
|
||||
}
|
||||
logWriting = true;
|
||||
// vedo se loggare...
|
||||
DateTime adesso = DateTime.Now;
|
||||
if (adesso.Subtract(lastLog).TotalSeconds > 15)
|
||||
{
|
||||
lastLog = adesso;
|
||||
logInfo(lineSep);
|
||||
|
||||
// lavoro su copia...
|
||||
var LogSimulatorCopy = new Dictionary<string, int>(LogSimulator);
|
||||
foreach (var item in LogSimulatorCopy)
|
||||
{
|
||||
logInfo($"Redis mQueue {item.Key,-20}{item.Value,12}");
|
||||
}
|
||||
logInfo(lineSep);
|
||||
}
|
||||
logWriting = false;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logError($"ERROR{Environment.NewLine}{ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+687
-238
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
* Copyright (c) 2005-2020 The OPC Foundation, Inc. All rights reserved.
|
||||
*
|
||||
* OPC Foundation MIT License 1.00
|
||||
*
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
@@ -11,7 +11,7 @@
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
@@ -27,22 +27,22 @@
|
||||
* http://opcfoundation.org/License/MIT/1.00/
|
||||
* ======================================================================*/
|
||||
|
||||
using Opc.Ua;
|
||||
using Opc.Ua.Client;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Opc.Ua;
|
||||
using Opc.Ua.Client;
|
||||
|
||||
namespace MP.MONO.ADAPTER.OPC
|
||||
{
|
||||
/// <summary>
|
||||
/// OPC UA Client with examples of basic functionality.
|
||||
/// </summary>
|
||||
class UAClient
|
||||
internal class UAClient
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the UAClient class.
|
||||
/// </summary>
|
||||
@@ -53,21 +53,98 @@ namespace MP.MONO.ADAPTER.OPC
|
||||
m_configuration = configuration;
|
||||
m_configuration.CertificateValidator.CertificateValidation += CertificateValidation;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Public Properties
|
||||
/// <summary>
|
||||
/// Auto accept untrusted certificates.
|
||||
/// </summary>
|
||||
public bool AutoAccept { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the client session.
|
||||
/// </summary>
|
||||
public Session Session => m_session;
|
||||
|
||||
/// <summary>
|
||||
/// Auto accept untrusted certificates.
|
||||
/// Browse Server nodes
|
||||
/// </summary>
|
||||
public bool AutoAccept { get; set; } = false;
|
||||
#endregion
|
||||
public void Browse()
|
||||
{
|
||||
if (m_session == null || m_session.Connected == false)
|
||||
{
|
||||
m_output.WriteLine("Session not connected!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Create a Browser object
|
||||
Browser browser = new Browser(m_session);
|
||||
|
||||
// Set browse parameters
|
||||
browser.BrowseDirection = BrowseDirection.Forward;
|
||||
browser.NodeClassMask = (int)NodeClass.Object | (int)NodeClass.Variable;
|
||||
browser.ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences;
|
||||
|
||||
NodeId nodeToBrowse = ObjectIds.Server;
|
||||
|
||||
// Call Browse service
|
||||
m_output.WriteLine("Browsing {0} node...", nodeToBrowse);
|
||||
ReferenceDescriptionCollection browseResults = browser.Browse(nodeToBrowse);
|
||||
|
||||
// Display the results
|
||||
m_output.WriteLine("Browse returned {0} results:", browseResults.Count);
|
||||
|
||||
foreach (ReferenceDescription result in browseResults)
|
||||
{
|
||||
m_output.WriteLine(" DisplayName = {0}, NodeClass = {1}", result.DisplayName.Text, result.NodeClass);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log Error
|
||||
m_output.WriteLine($"Browse Error : {ex.Message}.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call UA method
|
||||
/// </summary>
|
||||
public void CallMethod()
|
||||
{
|
||||
if (m_session == null || m_session.Connected == false)
|
||||
{
|
||||
m_output.WriteLine("Session not connected!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Define the UA Method to call Parent node - Objects\CTT\Methods Method node - Objects\CTT\Methods\Add
|
||||
NodeId objectId = new NodeId("ns=2;s=Methods");
|
||||
NodeId methodId = new NodeId("ns=2;s=Methods_Add");
|
||||
|
||||
// Define the method parameters Input argument requires a Float and an UInt32 value
|
||||
object[] inputArguments = new object[] { (float)10.5, (uint)10 };
|
||||
IList<object> outputArguments = null;
|
||||
|
||||
// Invoke Call service
|
||||
m_output.WriteLine("Calling UAMethod for node {0} ...", methodId);
|
||||
outputArguments = m_session.Call(objectId, methodId, inputArguments);
|
||||
|
||||
// Display results
|
||||
m_output.WriteLine("Method call returned {0} output argument(s):", outputArguments.Count);
|
||||
|
||||
foreach (var outputArgument in outputArguments)
|
||||
{
|
||||
m_output.WriteLine(" OutputValue = {0}", outputArgument.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_output.WriteLine("Method call error: {0}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#region Public Methods
|
||||
/// <summary>
|
||||
/// Creates a session with the UA server
|
||||
/// </summary>
|
||||
@@ -85,8 +162,8 @@ namespace MP.MONO.ADAPTER.OPC
|
||||
{
|
||||
m_output.WriteLine("Connecting to... {0}", serverUrl);
|
||||
|
||||
// Get the endpoint by connecting to server's discovery endpoint.
|
||||
// Try to find the first endopint with security.
|
||||
// Get the endpoint by connecting to server's discovery endpoint. Try to find
|
||||
// the first endopint with security.
|
||||
EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint(m_configuration, serverUrl, true);
|
||||
EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(m_configuration);
|
||||
ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);
|
||||
@@ -166,7 +243,6 @@ namespace MP.MONO.ADAPTER.OPC
|
||||
|
||||
try
|
||||
{
|
||||
#region Read a node by calling the Read Service
|
||||
|
||||
// build a list of nodes to be read
|
||||
ReadValueIdCollection nodesToRead = new ReadValueIdCollection()
|
||||
@@ -199,15 +275,13 @@ namespace MP.MONO.ADAPTER.OPC
|
||||
{
|
||||
m_output.WriteLine("Read Value = {0} , StatusCode = {1}", result.Value, result.StatusCode);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Read the Value attribute of a node by calling the Session.ReadValue method
|
||||
// Read Server NamespaceArray
|
||||
m_output.WriteLine("Reading Value of NamespaceArray node...");
|
||||
DataValue namespaceArray = m_session.ReadValue(Variables.Server_NamespaceArray);
|
||||
// Display the result
|
||||
m_output.WriteLine($"NamespaceArray Value = {namespaceArray}");
|
||||
#endregion
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -216,159 +290,6 @@ namespace MP.MONO.ADAPTER.OPC
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a list of nodes to the Server
|
||||
/// </summary>
|
||||
public void WriteNodes()
|
||||
{
|
||||
if (m_session == null || m_session.Connected == false)
|
||||
{
|
||||
m_output.WriteLine("Session not connected!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Write the configured nodes
|
||||
WriteValueCollection nodesToWrite = new WriteValueCollection();
|
||||
|
||||
// Int32 Node - Objects\CTT\Scalar\Scalar_Static\Int32
|
||||
WriteValue intWriteVal = new WriteValue();
|
||||
intWriteVal.NodeId = new NodeId("ns=2;s=Scalar_Static_Int32");
|
||||
intWriteVal.AttributeId = Attributes.Value;
|
||||
intWriteVal.Value = new DataValue();
|
||||
intWriteVal.Value.Value = (int)100;
|
||||
nodesToWrite.Add(intWriteVal);
|
||||
|
||||
// Float Node - Objects\CTT\Scalar\Scalar_Static\Float
|
||||
WriteValue floatWriteVal = new WriteValue();
|
||||
floatWriteVal.NodeId = new NodeId("ns=2;s=Scalar_Static_Float");
|
||||
floatWriteVal.AttributeId = Attributes.Value;
|
||||
floatWriteVal.Value = new DataValue();
|
||||
floatWriteVal.Value.Value = (float)100.5;
|
||||
nodesToWrite.Add(floatWriteVal);
|
||||
|
||||
// String Node - Objects\CTT\Scalar\Scalar_Static\String
|
||||
WriteValue stringWriteVal = new WriteValue();
|
||||
stringWriteVal.NodeId = new NodeId("ns=2;s=Scalar_Static_String");
|
||||
stringWriteVal.AttributeId = Attributes.Value;
|
||||
stringWriteVal.Value = new DataValue();
|
||||
stringWriteVal.Value.Value = "String Test";
|
||||
nodesToWrite.Add(stringWriteVal);
|
||||
|
||||
// Write the node attributes
|
||||
StatusCodeCollection results = null;
|
||||
DiagnosticInfoCollection diagnosticInfos;
|
||||
m_output.WriteLine("Writing nodes...");
|
||||
|
||||
// Call Write Service
|
||||
m_session.Write(null,
|
||||
nodesToWrite,
|
||||
out results,
|
||||
out diagnosticInfos);
|
||||
|
||||
// Validate the response
|
||||
m_validateResponse(results, nodesToWrite);
|
||||
|
||||
// Display the results.
|
||||
m_output.WriteLine("Write Results :");
|
||||
|
||||
foreach (StatusCode writeResult in results)
|
||||
{
|
||||
m_output.WriteLine(" {0}", writeResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log Error
|
||||
m_output.WriteLine($"Write Nodes Error : {ex.Message}.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Browse Server nodes
|
||||
/// </summary>
|
||||
public void Browse()
|
||||
{
|
||||
if (m_session == null || m_session.Connected == false)
|
||||
{
|
||||
m_output.WriteLine("Session not connected!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Create a Browser object
|
||||
Browser browser = new Browser(m_session);
|
||||
|
||||
// Set browse parameters
|
||||
browser.BrowseDirection = BrowseDirection.Forward;
|
||||
browser.NodeClassMask = (int)NodeClass.Object | (int)NodeClass.Variable;
|
||||
browser.ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences;
|
||||
|
||||
NodeId nodeToBrowse = ObjectIds.Server;
|
||||
|
||||
// Call Browse service
|
||||
m_output.WriteLine("Browsing {0} node...", nodeToBrowse);
|
||||
ReferenceDescriptionCollection browseResults = browser.Browse(nodeToBrowse);
|
||||
|
||||
// Display the results
|
||||
m_output.WriteLine("Browse returned {0} results:", browseResults.Count);
|
||||
|
||||
foreach (ReferenceDescription result in browseResults)
|
||||
{
|
||||
m_output.WriteLine(" DisplayName = {0}, NodeClass = {1}", result.DisplayName.Text, result.NodeClass);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Log Error
|
||||
m_output.WriteLine($"Browse Error : {ex.Message}.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call UA method
|
||||
/// </summary>
|
||||
public void CallMethod()
|
||||
{
|
||||
if (m_session == null || m_session.Connected == false)
|
||||
{
|
||||
m_output.WriteLine("Session not connected!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Define the UA Method to call
|
||||
// Parent node - Objects\CTT\Methods
|
||||
// Method node - Objects\CTT\Methods\Add
|
||||
NodeId objectId = new NodeId("ns=2;s=Methods");
|
||||
NodeId methodId = new NodeId("ns=2;s=Methods_Add");
|
||||
|
||||
// Define the method parameters
|
||||
// Input argument requires a Float and an UInt32 value
|
||||
object[] inputArguments = new object[] { (float)10.5, (uint)10 };
|
||||
IList<object> outputArguments = null;
|
||||
|
||||
// Invoke Call service
|
||||
m_output.WriteLine("Calling UAMethod for node {0} ...", methodId);
|
||||
outputArguments = m_session.Call(objectId, methodId, inputArguments);
|
||||
|
||||
// Display results
|
||||
m_output.WriteLine("Method call returned {0} output argument(s):", outputArguments.Count);
|
||||
|
||||
foreach (var outputArgument in outputArguments)
|
||||
{
|
||||
m_output.WriteLine(" OutputValue = {0}", outputArgument.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_output.WriteLine("Method call error: {0}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create Subscription and MonitoredItems for DataChanges
|
||||
/// </summary>
|
||||
@@ -438,39 +359,95 @@ namespace MP.MONO.ADAPTER.OPC
|
||||
m_output.WriteLine("Subscribe error: {0}", ex.Message);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
/// <summary>
|
||||
/// Handle DataChange notifications from Server
|
||||
/// Write a list of nodes to the Server
|
||||
/// </summary>
|
||||
private void OnMonitoredItemNotification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
|
||||
public void WriteNodes()
|
||||
{
|
||||
if (m_session == null || m_session.Connected == false)
|
||||
{
|
||||
m_output.WriteLine("Session not connected!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Log MonitoredItem Notification event
|
||||
MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification;
|
||||
m_output.WriteLine("Notification Received for Variable \"{0}\" and Value = {1}.", monitoredItem.DisplayName, notification.Value);
|
||||
// Write the configured nodes
|
||||
WriteValueCollection nodesToWrite = new WriteValueCollection();
|
||||
|
||||
// Int32 Node - Objects\CTT\Scalar\Scalar_Static\Int32
|
||||
WriteValue intWriteVal = new WriteValue();
|
||||
intWriteVal.NodeId = new NodeId("ns=2;s=Scalar_Static_Int32");
|
||||
intWriteVal.AttributeId = Attributes.Value;
|
||||
intWriteVal.Value = new DataValue();
|
||||
intWriteVal.Value.Value = (int)100;
|
||||
nodesToWrite.Add(intWriteVal);
|
||||
|
||||
// Float Node - Objects\CTT\Scalar\Scalar_Static\Float
|
||||
WriteValue floatWriteVal = new WriteValue();
|
||||
floatWriteVal.NodeId = new NodeId("ns=2;s=Scalar_Static_Float");
|
||||
floatWriteVal.AttributeId = Attributes.Value;
|
||||
floatWriteVal.Value = new DataValue();
|
||||
floatWriteVal.Value.Value = (float)100.5;
|
||||
nodesToWrite.Add(floatWriteVal);
|
||||
|
||||
// String Node - Objects\CTT\Scalar\Scalar_Static\String
|
||||
WriteValue stringWriteVal = new WriteValue();
|
||||
stringWriteVal.NodeId = new NodeId("ns=2;s=Scalar_Static_String");
|
||||
stringWriteVal.AttributeId = Attributes.Value;
|
||||
stringWriteVal.Value = new DataValue();
|
||||
stringWriteVal.Value.Value = "String Test";
|
||||
nodesToWrite.Add(stringWriteVal);
|
||||
|
||||
// Write the node attributes
|
||||
StatusCodeCollection results = null;
|
||||
DiagnosticInfoCollection diagnosticInfos;
|
||||
m_output.WriteLine("Writing nodes...");
|
||||
|
||||
// Call Write Service
|
||||
m_session.Write(null,
|
||||
nodesToWrite,
|
||||
out results,
|
||||
out diagnosticInfos);
|
||||
|
||||
// Validate the response
|
||||
m_validateResponse(results, nodesToWrite);
|
||||
|
||||
// Display the results.
|
||||
m_output.WriteLine("Write Results :");
|
||||
|
||||
foreach (StatusCode writeResult in results)
|
||||
{
|
||||
m_output.WriteLine(" {0}", writeResult);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_output.WriteLine("OnMonitoredItemNotification error: {0}", ex.Message);
|
||||
// Log Error
|
||||
m_output.WriteLine($"Write Nodes Error : {ex.Message}.");
|
||||
}
|
||||
}
|
||||
|
||||
private readonly TextWriter m_output;
|
||||
|
||||
private readonly Action<IList, IList> m_validateResponse;
|
||||
|
||||
private ApplicationConfiguration m_configuration;
|
||||
|
||||
private Session m_session;
|
||||
|
||||
/// <summary>
|
||||
/// Handles the certificate validation event.
|
||||
/// This event is triggered every time an untrusted certificate is received from the server.
|
||||
/// Handles the certificate validation event. This event is triggered every time an
|
||||
/// untrusted certificate is received from the server.
|
||||
/// </summary>
|
||||
private void CertificateValidation(CertificateValidator sender, CertificateValidationEventArgs e)
|
||||
{
|
||||
bool certificateAccepted = false;
|
||||
|
||||
// ****
|
||||
// Implement a custom logic to decide if the certificate should be
|
||||
// accepted or not and set certificateAccepted flag accordingly.
|
||||
// The certificate can be retrieved from the e.Certificate field
|
||||
// ***
|
||||
// **** Implement a custom logic to decide if the certificate should be accepted or not
|
||||
// and set certificateAccepted flag accordingly. The certificate can be retrieved from
|
||||
// the e.Certificate field ***
|
||||
|
||||
ServiceResult error = e.Error;
|
||||
m_output.WriteLine(error);
|
||||
@@ -489,13 +466,23 @@ namespace MP.MONO.ADAPTER.OPC
|
||||
m_output.WriteLine("Untrusted Certificate rejected. Subject = {0}", e.Certificate.Subject);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Private Fields
|
||||
private ApplicationConfiguration m_configuration;
|
||||
private Session m_session;
|
||||
private readonly TextWriter m_output;
|
||||
private readonly Action<IList, IList> m_validateResponse;
|
||||
#endregion
|
||||
/// <summary>
|
||||
/// Handle DataChange notifications from Server
|
||||
/// </summary>
|
||||
private void OnMonitoredItemNotification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Log MonitoredItem Notification event
|
||||
MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification;
|
||||
m_output.WriteLine("Notification Received for Variable \"{0}\" and Value = {1}.", monitoredItem.DisplayName, notification.Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_output.WriteLine("OnMonitoredItemNotification error: {0}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"ConnectionStrings": {
|
||||
"Redis": "nkcredis.steamware.net:6379,DefaultDatabase=7,connectTimeout=5000,syncTimeout=5000,asyncTimeout=5000,abortConnect=false,ssl=false,password=nkc.password",
|
||||
"AuthConnection": "Server=localhost;port=3306;database=GWMS;user=GWMS;pwd=GWMS_secret_pwd;sslmode=None;",
|
||||
"DefaultConnection": "Server=localhost;port=3306;database=MAPO.MONO;user=GWMS;pwd=GWMS_secret_pwd;sslmode=None;",
|
||||
"AdminConnection": "Server=localhost;port=3306;database=MAPO.MONO;user=root;pwd=Egalware_24068!;sslmode=None;",
|
||||
"MP.MONO.Data": "Server=localhost;port=3306;database=MAPO.MONO;user=GWMS;pwd=GWMS_secret_pwd;sslmode=None;"
|
||||
},
|
||||
"DbConfig": {
|
||||
"Server": "10.74.82.230",
|
||||
"nKey": "MONO",
|
||||
"sKey": "Calcium0xide-CaO"
|
||||
},
|
||||
"MachineId": 1,
|
||||
"maxRecord": 15,
|
||||
"ExternalProviders": {
|
||||
"MailKit": {
|
||||
"SMTP": {
|
||||
"Address": "smtp.gmail.com",
|
||||
"Port": "465",
|
||||
"Account": "steamwarebot@gmail.com",
|
||||
"Password": "drmfsls16",
|
||||
"SenderEmail": "steamwarebot@gmail.com",
|
||||
"SenderName": "Steamware Email BOT"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Endpoint": {
|
||||
"IpAddress": "192.168.0.2",
|
||||
"Port": "4840",
|
||||
"PingMsTimeout": 1500
|
||||
},
|
||||
"ENABLE_DATA_FILTER": true,
|
||||
"ENABLE_CLI_RESTART": true,
|
||||
"logEvery": 10,
|
||||
"OPC_PARAM_CONF": "MULTIAX.json",
|
||||
"pingTestSec": 5,
|
||||
"verbose": false,
|
||||
"disconMaxSec": 30,
|
||||
"verboseLogTOut": 60,
|
||||
"waitRecMSec": 60000
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(AppTargetFrameWorks)</TargetFrameworks>
|
||||
<AssemblyName>MP.MONO.ADAPTER.OPC</AssemblyName>
|
||||
<OutputType>Exe</OutputType>
|
||||
<PackageId>MP.MONO.ADAPTER.OPC</PackageId>
|
||||
<Company>EgalWare</Company>
|
||||
<Description>OPC UA Console Client</Description>
|
||||
<Copyright>Copyright © 2020+ EgalWare</Copyright>
|
||||
<RootNamespace>MP.MONO.ADAPTER.OPC</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(NoHttps)' != 'true' ">
|
||||
<ProjectReference Include="..\..\Stack\Opc.Ua.Bindings.Https\Opc.Ua.Bindings.Https.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\ConsoleReferenceServer\ConsoleUtils.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
<PackageReference Include="Mono.Options" Version="6.12.0.148" />
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog.Expressions" Version="3.3.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Stack\Opc.Ua.Core\Opc.Ua.Core.csproj" />
|
||||
<ProjectReference Include="..\..\Libraries\Opc.Ua.Configuration\Opc.Ua.Configuration.csproj" />
|
||||
<ProjectReference Include="..\..\Libraries\Opc.Ua.Client\Opc.Ua.Client.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="MP.MONO.ADAPTER.OPC.Config.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,89 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ApplicationConfiguration
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:ua="http://opcfoundation.org/UA/2008/02/Types.xsd"
|
||||
xmlns="http://opcfoundation.org/UA/SDK/Configuration.xsd"
|
||||
>
|
||||
<ApplicationName>Quickstart Console Reference Client</ApplicationName>
|
||||
<ApplicationUri>urn:localhost:UA:Quickstarts:ReferenceClient</ApplicationUri>
|
||||
<ProductUri>uri:opcfoundation.org:Quickstarts:ReferenceClient</ProductUri>
|
||||
<ApplicationType>Client_1</ApplicationType>
|
||||
|
||||
<SecurityConfiguration>
|
||||
|
||||
<!-- Where the application instance certificate is stored (MachineDefault) -->
|
||||
<ApplicationCertificate>
|
||||
<StoreType>Directory</StoreType>
|
||||
<StorePath>%LocalApplicationData%/OPC Foundation/pki/own</StorePath>
|
||||
<SubjectName>CN=Console Reference Client, C=US, S=Arizona, O=OPC Foundation, DC=localhost</SubjectName>
|
||||
</ApplicationCertificate>
|
||||
|
||||
<!-- Where the issuer certificate are stored (certificate authorities) -->
|
||||
<TrustedIssuerCertificates>
|
||||
<StoreType>Directory</StoreType>
|
||||
<StorePath>%LocalApplicationData%/OPC Foundation/pki/issuer</StorePath>
|
||||
</TrustedIssuerCertificates>
|
||||
|
||||
<!-- Where the trust list is stored -->
|
||||
<TrustedPeerCertificates>
|
||||
<StoreType>Directory</StoreType>
|
||||
<StorePath>%LocalApplicationData%/OPC Foundation/pki/trusted</StorePath>
|
||||
</TrustedPeerCertificates>
|
||||
|
||||
<!-- The directory used to store invalid certficates for later review by the administrator. -->
|
||||
<RejectedCertificateStore>
|
||||
<StoreType>Directory</StoreType>
|
||||
<StorePath>%LocalApplicationData%/OPC Foundation/pki/rejected</StorePath>
|
||||
</RejectedCertificateStore>
|
||||
|
||||
<!-- WARNING: The following setting (to automatically accept untrusted certificates) should be used
|
||||
for easy debugging purposes ONLY and turned off for production deployments! -->
|
||||
<AutoAcceptUntrustedCertificates>false</AutoAcceptUntrustedCertificates>
|
||||
|
||||
</SecurityConfiguration>
|
||||
|
||||
<TransportConfigurations></TransportConfigurations>
|
||||
|
||||
<TransportQuotas>
|
||||
<OperationTimeout>600000</OperationTimeout>
|
||||
<MaxStringLength>1048576</MaxStringLength>
|
||||
<MaxByteStringLength>1048576</MaxByteStringLength>
|
||||
<MaxArrayLength>65535</MaxArrayLength>
|
||||
<MaxMessageSize>4194304</MaxMessageSize>
|
||||
<MaxBufferSize>65535</MaxBufferSize>
|
||||
<ChannelLifetime>300000</ChannelLifetime>
|
||||
<SecurityTokenLifetime>3600000</SecurityTokenLifetime>
|
||||
</TransportQuotas>
|
||||
|
||||
<ClientConfiguration>
|
||||
<DefaultSessionTimeout>60000</DefaultSessionTimeout>
|
||||
<WellKnownDiscoveryUrls>
|
||||
<ua:String>opc.tcp://{0}:4840</ua:String>
|
||||
<ua:String>http://{0}:52601/UADiscovery</ua:String>
|
||||
<ua:String>http://{0}/UADiscovery/Default.svc</ua:String>
|
||||
</WellKnownDiscoveryUrls>
|
||||
<DiscoveryServers></DiscoveryServers>
|
||||
<MinSubscriptionLifetime>10000</MinSubscriptionLifetime>
|
||||
</ClientConfiguration>
|
||||
|
||||
<Extensions>
|
||||
</Extensions>
|
||||
|
||||
<TraceConfiguration>
|
||||
<OutputFilePath>%LocalApplicationData%/OPC Foundation/Logs/Quickstarts.ReferenceClient.log.txt</OutputFilePath>
|
||||
<DeleteOnLoad>true</DeleteOnLoad>
|
||||
<!-- Show Only Errors -->
|
||||
<!-- <TraceMasks>1</TraceMasks> -->
|
||||
<!-- Show Only Security and Errors -->
|
||||
<!-- <TraceMasks>513</TraceMasks> -->
|
||||
<!-- Show Only Security, Errors and Trace -->
|
||||
<!-- <TraceMasks>515</TraceMasks> -->
|
||||
<!-- Show Only Security, COM Calls, Errors and Trace -->
|
||||
<!-- <TraceMasks>771</TraceMasks> -->
|
||||
<!-- Show Only Security, Service Calls, Errors and Trace -->
|
||||
<!-- <TraceMasks>523</TraceMasks> -->
|
||||
<!-- Show Only Security, ServiceResultExceptions, Errors and Trace -->
|
||||
<!-- <TraceMasks>519</TraceMasks> -->
|
||||
</TraceConfiguration>
|
||||
|
||||
</ApplicationConfiguration>
|
||||
@@ -1,45 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>$(AppTargetFrameWorks)</TargetFrameworks>
|
||||
<AssemblyName>MP.MONO.ADAPTER.OPC</AssemblyName>
|
||||
<OutputType>Exe</OutputType>
|
||||
<PackageId>MP.MONO.ADAPTER.OPC</PackageId>
|
||||
<Company>EgalWare</Company>
|
||||
<Description>OPC UA Console Client</Description>
|
||||
<Copyright>Copyright © 2020+ EgalWare</Copyright>
|
||||
<RootNamespace>MP.MONO.ADAPTER.OPC</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(NoHttps)' != 'true' ">
|
||||
<ProjectReference Include="..\..\Stack\Opc.Ua.Bindings.Https\Opc.Ua.Bindings.Https.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\ConsoleReferenceServer\ConsoleUtils.cs" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
<PackageReference Include="Mono.Options" Version="6.12.0.148" />
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog.Expressions" Version="3.3.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
||||
<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Stack\Opc.Ua.Core\Opc.Ua.Core.csproj" />
|
||||
<ProjectReference Include="..\..\Libraries\Opc.Ua.Configuration\Opc.Ua.Configuration.csproj" />
|
||||
<ProjectReference Include="..\..\Libraries\Opc.Ua.Client\Opc.Ua.Client.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="MP.MONO.ADAPTER.OPC.Config.xml">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,186 +0,0 @@
|
||||
/* ========================================================================
|
||||
* Copyright (c) 2005-2021 The OPC Foundation, Inc. All rights reserved.
|
||||
*
|
||||
* OPC Foundation MIT License 1.00
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The complete license agreement can be found here:
|
||||
* http://opcfoundation.org/License/MIT/1.00/
|
||||
* ======================================================================*/
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Opc.Ua;
|
||||
using Opc.Ua.Configuration;
|
||||
|
||||
namespace MP.MONO.ADAPTER.OPC
|
||||
{
|
||||
/// <summary>
|
||||
/// The program.
|
||||
/// </summary>
|
||||
public static class Program
|
||||
{
|
||||
/// <summary>
|
||||
/// Main entry point.
|
||||
/// </summary>
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
TextWriter output = Console.Out;
|
||||
output.WriteLine("OPC UA Console Reference Client");
|
||||
|
||||
output.WriteLine("OPC UA library: {0} @ {1} -- {2}",
|
||||
Utils.GetAssemblyBuildNumber(),
|
||||
Utils.GetAssemblyTimestamp().ToString("G", CultureInfo.InvariantCulture),
|
||||
Utils.GetAssemblySoftwareVersion());
|
||||
|
||||
// The application name and config file names
|
||||
var applicationName = "ConsoleReferenceClient";
|
||||
var configSectionName = "Quickstarts.ReferenceClient";
|
||||
var usage = $"Usage: dotnet {applicationName}.dll [OPTIONS]";
|
||||
|
||||
// command line options
|
||||
bool showHelp = false;
|
||||
bool autoAccept = false;
|
||||
bool logConsole = false;
|
||||
bool appLog = false;
|
||||
bool renewCertificate = false;
|
||||
string password = null;
|
||||
int timeout = Timeout.Infinite;
|
||||
|
||||
Mono.Options.OptionSet options = new Mono.Options.OptionSet {
|
||||
usage,
|
||||
{ "h|help", "show this message and exit", h => showHelp = h != null },
|
||||
{ "a|autoaccept", "auto accept certificates (for testing only)", a => autoAccept = a != null },
|
||||
{ "c|console", "log to console", c => logConsole = c != null },
|
||||
{ "l|log", "log app output", c => appLog = c != null },
|
||||
{ "p|password=", "optional password for private key", (string p) => password = p },
|
||||
{ "r|renew", "renew application certificate", r => renewCertificate = r != null },
|
||||
{ "t|timeout=", "timeout in seconds to exit application", (int t) => timeout = t * 1000 },
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
// parse command line and set options
|
||||
var extraArg = ConsoleUtils.ProcessCommandLine(output, args, options, ref showHelp, false);
|
||||
|
||||
// connect Url?
|
||||
Uri serverUrl = new Uri("opc.tcp://localhost:62541/Quickstarts/ReferenceServer");
|
||||
if (!string.IsNullOrEmpty(extraArg))
|
||||
{
|
||||
serverUrl = new Uri(extraArg);
|
||||
}
|
||||
|
||||
// log console output to logger
|
||||
if (logConsole && appLog)
|
||||
{
|
||||
output = new LogWriter();
|
||||
}
|
||||
|
||||
// Define the UA Client application
|
||||
ApplicationInstance.MessageDlg = new ApplicationMessageDlg(output);
|
||||
CertificatePasswordProvider PasswordProvider = new CertificatePasswordProvider(password);
|
||||
ApplicationInstance application = new ApplicationInstance {
|
||||
ApplicationName = applicationName,
|
||||
ApplicationType = ApplicationType.Client,
|
||||
ConfigSectionName = configSectionName,
|
||||
CertificatePasswordProvider = PasswordProvider
|
||||
};
|
||||
|
||||
// load the application configuration.
|
||||
var config = await application.LoadApplicationConfiguration(silent: false);
|
||||
|
||||
// setup the logging
|
||||
ConsoleUtils.ConfigureLogging(config, applicationName, logConsole, LogLevel.Information);
|
||||
|
||||
// delete old certificate
|
||||
if (renewCertificate)
|
||||
{
|
||||
await application.DeleteApplicationInstanceCertificate().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// check the application certificate.
|
||||
bool haveAppCertificate = await application.CheckApplicationInstanceCertificate(false, minimumKeySize: 0).ConfigureAwait(false);
|
||||
if (!haveAppCertificate)
|
||||
{
|
||||
throw new ErrorExitException("Application instance certificate invalid!", ExitCode.ErrorCertificate);
|
||||
}
|
||||
|
||||
// wait for timeout or Ctrl-C
|
||||
var quitEvent = ConsoleUtils.CtrlCHandler();
|
||||
|
||||
// connect to a server until application stopped
|
||||
bool quit = false;
|
||||
DateTime start = DateTime.UtcNow;
|
||||
int waitTime = int.MaxValue;
|
||||
do
|
||||
{
|
||||
if (timeout > 0)
|
||||
{
|
||||
waitTime = timeout - (int)DateTime.UtcNow.Subtract(start).TotalMilliseconds;
|
||||
if (waitTime <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// create the UA Client object and connect to configured server.
|
||||
UAClient uaClient = new UAClient(application.ApplicationConfiguration, output, ClientBase.ValidateResponse) {
|
||||
AutoAccept = autoAccept
|
||||
};
|
||||
|
||||
bool connected = await uaClient.ConnectAsync(serverUrl.ToString());
|
||||
if (connected)
|
||||
{
|
||||
// Run tests for available methods.
|
||||
uaClient.ReadNodes();
|
||||
uaClient.WriteNodes();
|
||||
uaClient.Browse();
|
||||
uaClient.CallMethod();
|
||||
|
||||
uaClient.SubscribeToDataChanges();
|
||||
|
||||
// Wait for some DataChange notifications from MonitoredItems
|
||||
quit = quitEvent.WaitOne(Math.Min(30_000, waitTime));
|
||||
|
||||
uaClient.Disconnect();
|
||||
}
|
||||
else
|
||||
{
|
||||
output.WriteLine("Could not connect to server! Retry in 10 seconds or Ctrl-C to quit.");
|
||||
quit = quitEvent.WaitOne(Math.Min(10_000, waitTime));
|
||||
}
|
||||
|
||||
} while (!quit);
|
||||
|
||||
output.WriteLine("\nClient stopped.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
output.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
REM collect a trace using the EventSource provider OPC-UA-Core
|
||||
dotnet tool install --global dotnet-trace
|
||||
dotnet-trace collect --name consolereferenceclient --providers OPC-UA-Core,OPC-UA-Client
|
||||
@@ -1,44 +0,0 @@
|
||||
<Project>
|
||||
<!-- Uncomment to suppress warning that .NET Core 2.1 is used with .NET 6 library. -->
|
||||
<!--
|
||||
<PropertyGroup>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
</PropertyGroup>
|
||||
-->
|
||||
<Choose>
|
||||
<!-- Note: .NET Core 2.x is end of life, removed netcoreapp2.1 from any target. -->
|
||||
<!-- Visual Studio 2022, supports .NET Framework 4.6.2, .NET Core 3.1 and .NET 6 -->
|
||||
<When Condition="'$(VisualStudioVersion)' == '17.0'">
|
||||
<PropertyGroup>
|
||||
<AppTargetFrameworks>net6.0;netcoreapp3.1;net462</AppTargetFrameworks>
|
||||
<AppTargetFramework>net6.0</AppTargetFramework>
|
||||
<TestsTargetFrameworks>net462;netcoreapp3.1;net6.0</TestsTargetFrameworks>
|
||||
<LibTargetFrameworks>net462;netstandard2.0;netstandard2.1;net6.0</LibTargetFrameworks>
|
||||
<LibxTargetFrameworks>net462;netstandard2.1;net6.0</LibxTargetFrameworks>
|
||||
<HttpsTargetFrameworks>net462;netstandard2.0;netcoreapp3.1;net6.0</HttpsTargetFrameworks>
|
||||
</PropertyGroup>
|
||||
</When>
|
||||
<!-- Visual Studio 2019, supports .NET Framework 4.6.2 and .NET Core 3.1 -->
|
||||
<When Condition="'$(VisualStudioVersion)' == '16.0'">
|
||||
<PropertyGroup>
|
||||
<AppTargetFrameworks>netcoreapp3.1;net462</AppTargetFrameworks>
|
||||
<AppTargetFramework>netcoreapp3.1</AppTargetFramework>
|
||||
<TestsTargetFrameworks>net462;netcoreapp3.1</TestsTargetFrameworks>
|
||||
<LibTargetFrameworks>net462;netstandard2.0;netstandard2.1</LibTargetFrameworks>
|
||||
<LibxTargetFrameworks>net462;netstandard2.1</LibxTargetFrameworks>
|
||||
<HttpsTargetFrameworks>net462;netstandard2.0;netcoreapp3.1</HttpsTargetFrameworks>
|
||||
</PropertyGroup>
|
||||
</When>
|
||||
<!-- Visual Studio 2017 and earlier, support only .NET Framework 4.6.2 because .NET Core 2.x is end of life. -->
|
||||
<Otherwise>
|
||||
<PropertyGroup>
|
||||
<AppTargetFrameworks>net462</AppTargetFrameworks>
|
||||
<AppTargetFramework>net462</AppTargetFramework>
|
||||
<TestsTargetFrameworks>net462</TestsTargetFrameworks>
|
||||
<LibTargetFrameworks>net462</LibTargetFrameworks>
|
||||
<LibxTargetFrameworks>net462</LibxTargetFrameworks>
|
||||
<HttpsTargetFrameworks>net462</HttpsTargetFrameworks>
|
||||
</PropertyGroup>
|
||||
</Otherwise>
|
||||
</Choose>
|
||||
</Project>
|
||||
@@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MP.MONO.DECODER", "MP.MONO.
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MP.MONO.ANALYZER", "MP.MONO.ANALYZER\MP.MONO.ANALYZER.csproj", "{4C9BEAED-1A33-41A7-B9D6-7C173A43FDB8}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MP.MONO.ADAPTER.OPC", "MP.MONO.ADAPTER.OPC\MP.MONO.ADAPTER.OPC.csproj", "{FA236252-9AF8-426A-8A0A-D3C234441563}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -97,6 +99,18 @@ Global
|
||||
{4C9BEAED-1A33-41A7-B9D6-7C173A43FDB8}.Release|x64.Build.0 = Release|x64
|
||||
{4C9BEAED-1A33-41A7-B9D6-7C173A43FDB8}.Release|x86.ActiveCfg = Release|x86
|
||||
{4C9BEAED-1A33-41A7-B9D6-7C173A43FDB8}.Release|x86.Build.0 = Release|x86
|
||||
{FA236252-9AF8-426A-8A0A-D3C234441563}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FA236252-9AF8-426A-8A0A-D3C234441563}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FA236252-9AF8-426A-8A0A-D3C234441563}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{FA236252-9AF8-426A-8A0A-D3C234441563}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{FA236252-9AF8-426A-8A0A-D3C234441563}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{FA236252-9AF8-426A-8A0A-D3C234441563}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{FA236252-9AF8-426A-8A0A-D3C234441563}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FA236252-9AF8-426A-8A0A-D3C234441563}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FA236252-9AF8-426A-8A0A-D3C234441563}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{FA236252-9AF8-426A-8A0A-D3C234441563}.Release|x64.Build.0 = Release|Any CPU
|
||||
{FA236252-9AF8-426A-8A0A-D3C234441563}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{FA236252-9AF8-426A-8A0A-D3C234441563}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>AnyCPU;x86;x64</Platforms>
|
||||
<Version>1.12206.1319</Version>
|
||||
<Version>1.12206.1419</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>MAPO-MONO</i>
|
||||
<h4>Version: 1.12206.1319</h4>
|
||||
<h4>Version: 1.12206.1419</h4>
|
||||
<br /> Release Note:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.12206.1319
|
||||
1.12206.1419
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>1.12206.1319</version>
|
||||
<version>1.12206.1419</version>
|
||||
<url>http://nexus.steamware.net/repository/SWS/MP.MONO.ANALYZER/stable/LAST/MP.Mon.zip</url>
|
||||
<changelog>http://nexus.steamware.net/repository/SWS/MP.MONO.ANALYZER/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
using static MP.MONO.Core.Enums;
|
||||
|
||||
namespace MP.MONO.Core.CONF
|
||||
{
|
||||
/// <summary>
|
||||
/// Descrittore oggetto DataItem generico
|
||||
/// </summary>
|
||||
public class MachDataItem
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public MachDataItem()
|
||||
{ }
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Categoria oggetto
|
||||
/// </summary>
|
||||
public DataItemCategory Category { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Nome / descrizione
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tipologia specifica
|
||||
/// </summary>
|
||||
public string SubType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Tipologia principale
|
||||
/// </summary>
|
||||
public string Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unità di misura
|
||||
/// </summary>
|
||||
public string Units { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ID generico
|
||||
/// </summary>
|
||||
public string uuid { get; set; }
|
||||
|
||||
#endregion Public Properties
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,16 @@
|
||||
OR
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Categoria dataItem
|
||||
/// </summary>
|
||||
public enum DataItemCategory
|
||||
{
|
||||
CONDITION = 0,
|
||||
EVENT = 1,
|
||||
SAMPLE = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ENUM degli stati (es path OPC-UA)
|
||||
/// </summary>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>AnyCPU;x86;x64</Platforms>
|
||||
<Version>1.12206.1319</Version>
|
||||
<Version>1.12206.1419</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>MAPO-MONO</i>
|
||||
<h4>Version: 1.12206.1319</h4>
|
||||
<h4>Version: 1.12206.1419</h4>
|
||||
<br /> Release Note:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.12206.1319
|
||||
1.12206.1419
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>1.12206.1319</version>
|
||||
<version>1.12206.1419</version>
|
||||
<url>http://nexus.steamware.net/repository/SWS/MP.MONO.DECODER/stable/LAST/MP.Mon.zip</url>
|
||||
<changelog>http://nexus.steamware.net/repository/SWS/MP.MONO.DECODER/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>AnyCPU;x86;x64</Platforms>
|
||||
<Version>1.12206.1319</Version>
|
||||
<Version>1.12206.1419</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>MAPO-MONO</i>
|
||||
<h4>Version: 1.12206.1319</h4>
|
||||
<h4>Version: 1.12206.1419</h4>
|
||||
<br /> Release Note:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.12206.1319
|
||||
1.12206.1419
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>1.12206.1319</version>
|
||||
<version>1.12206.1419</version>
|
||||
<url>http://nexus.steamware.net/repository/SWS/MP.MONO.SIM/stable/LAST/MP.Mon.zip</url>
|
||||
<changelog>http://nexus.steamware.net/repository/SWS/MP.MONO.SIM/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Platforms>AnyCPU;x86;x64</Platforms>
|
||||
<Version>1.12206.1411</Version>
|
||||
<Version>1.12206.1419</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<body>
|
||||
<i>MAPO-MONO</i>
|
||||
<h4>Version: 1.12206.1411</h4>
|
||||
<h4>Version: 1.12206.1419</h4>
|
||||
<br /> Release Note:
|
||||
<ul>
|
||||
<li>
|
||||
|
||||
@@ -1 +1 @@
|
||||
1.12206.1411
|
||||
1.12206.1419
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<item>
|
||||
<version>1.12206.1411</version>
|
||||
<version>1.12206.1419</version>
|
||||
<url>http://nexus.steamware.net/repository/SWS/MP.MONO.UI/stable/LAST/MP.Mon.zip</url>
|
||||
<changelog>http://nexus.steamware.net/repository/SWS/MP.MONO.UI/stable/LAST/ChangeLog.html</changelog>
|
||||
<mandatory>false</mandatory>
|
||||
|
||||
Reference in New Issue
Block a user