protected override List <OpcNodeOnEndpointModel> GetConfiguredNodesOnEndpoint(string endpointUrl, CancellationToken ct) { string logPrefix = $"{_logClassPrefix}:GetConfiguredNodesOnEndpoint:"; Random random = new Random(); List <OpcNodeOnEndpointModel> nodeList = new List <OpcNodeOnEndpointModel>(); try { PublishedNodesCollection publishedNodes = GetPublishedNodesLegacy(endpointUrl, ct); foreach (var publishedNode in publishedNodes) { OpcNodeOnEndpointModel node = new OpcNodeOnEndpointModel(publishedNode.NodeID.ToString()); nodeList.Add(node); } } catch (Exception e) { Logger.Fatal(e, $"{logPrefix} Exception"); } return(nodeList); }
/// <summary> /// Asynchronous part of the main method of the app. /// </summary> public async static Task MainAsync(string[] args) { Logger = new LoggerConfiguration() .WriteTo.Console() .MinimumLevel.Debug() .CreateLogger(); Logger.Information($"OPC Publisher node configuration tool"); // command line options bool showHelp = false; string iotHubConnectionString = string.Empty; string iotHubPublisherDeviceName = string.Empty; string iotHubPublisherModuleName = string.Empty; Mono.Options.OptionSet options = new Mono.Options.OptionSet { { "h|help", "show this message and exit", h => showHelp = h != null }, { "ic|iotHubConnectionString=", "IoTHub owner or service connectionstring", (string s) => iotHubConnectionString = s }, { "id|iothubdevicename=", "IoTHub device name of the OPC Publisher", (string s) => iotHubPublisherDeviceName = s }, { "im|iothubmodulename=", "IoT Edge module name of the OPC Publisher which runs in the IoT Edge device specified by id/iothubdevicename", (string s) => iotHubPublisherModuleName = s }, { "pc|purgeconfig", "remove all configured nodes before pushing new ones", b => _purgeConfig = b != null }, { "bf|backupfile=", $"the filename to store the existing node configuration of OPC Publisher\nDefault: './{_backupFileName}'", (string l) => _backupFileName = l }, { "nc|nodeconfigfile=", $"the filename of the new node configuration to be set", (string l) => _nodeConfigFileName = l }, { "lf|logfile=", $"the filename of the logfile to use\nDefault: './{_logFileName}'", (string l) => _logFileName = l }, { "ll|loglevel=", $"the loglevel to use (allowed: fatal, error, warn, info, debug, verbose).\nDefault: info", (string l) => { List <string> logLevels = new List <string> { "fatal", "error", "warn", "info", "debug", "verbose" }; if (logLevels.Contains(l.ToLowerInvariant())) { _logLevel = l.ToLowerInvariant(); } else { throw new OptionException("The loglevel must be one of: fatal, error, warn, info, debug, verbose", "loglevel"); } } } }; IList <string> extraArgs = null; try { extraArgs = options.Parse(args); } catch (OptionException e) { // initialize logging InitLogging(); // show message Logger.Fatal(e, "Error in command line options"); // show usage Usage(options, args); return; } // initialize logging InitLogging(); // show usage if requested if (showHelp) { Usage(options); return; } // no extra options if (extraArgs.Count > 0) { for (int i = 1; i < extraArgs.Count; i++) { Logger.Error("Error: Unknown option: {0}", extraArgs[i]); } Usage(options, args); return; } // sanity check parameters if (string.IsNullOrEmpty(iotHubConnectionString) || string.IsNullOrEmpty(iotHubPublisherDeviceName)) { Logger.Fatal("For IoTHub communication an IoTHub connection string and the publisher devicename (and modulename) must be specified."); return; } Logger.Information($"IoTHub connectionstring: {iotHubConnectionString}"); if (string.IsNullOrEmpty(iotHubPublisherModuleName)) { Logger.Information($"OPC Publisher not running in IoT Edge."); Logger.Information($"IoTHub OPC Publisher device name: {iotHubPublisherDeviceName}"); } else { Logger.Information($"OPC Publisher running as IoT Edge module."); Logger.Information($"IoT Edge device name: {iotHubPublisherDeviceName}"); Logger.Information($"OPC Publisher module name: {iotHubPublisherModuleName}"); } CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken ct = cts.Token; // read new configuration if (!string.IsNullOrEmpty(_nodeConfigFileName)) { try { _configurationFileEntries = JsonConvert.DeserializeObject <List <PublisherConfigurationFileEntryLegacyModel> >(File.ReadAllText(_nodeConfigFileName)); } catch (Exception e) { Logger.Fatal(e, $"Error reading configuration file. Exiting..."); return; } Logger.Information($"The configuration file '{_nodeConfigFileName}' to be applied contains {_configurationFileEntries.Count} entries."); } // instantiate OPC Publisher interface Publisher publisher = new Publisher(iotHubConnectionString, iotHubPublisherDeviceName, iotHubPublisherModuleName, MAX_SHORT_WAIT_SEC, MAX_LONG_WAIT_SEC, ct); // read existing configuration List <PublisherConfigurationFileEntryModel> currentConfiguration = new List <PublisherConfigurationFileEntryModel>(); List <string> configuredEndpoints = publisher.GetConfiguredEndpoints(ct); if (configuredEndpoints.Count > 0) { Logger.Information($"OPC Publisher has the following node configuration:"); } else { Logger.Information($"OPC Publisher is not publishing any data."); } foreach (var configuredEndpoint in configuredEndpoints) { List <NodeModel> configuredNodesOnEndpoint = publisher.GetConfiguredNodesOnEndpoint(configuredEndpoint, ct); PublisherConfigurationFileEntryModel configEntry = new PublisherConfigurationFileEntryModel(); configEntry.EndpointUrl = new Uri(configuredEndpoint); List <OpcNodeOnEndpointModel> nodesOnEndpoint = new List <OpcNodeOnEndpointModel>(); Logger.Information($"For endpoint '{configuredEndpoint}' there are {configuredNodesOnEndpoint.Count} nodes configured."); foreach (var configuredNode in configuredNodesOnEndpoint) { Logger.Debug($"Id '{configuredNode.Id}', " + $"OpcPublishingInterval: {(configuredNode.OpcPublishingInterval == null ? "default" : configuredNode.OpcPublishingInterval.ToString())}, " + $"OpcSamplingInterval: {(configuredNode.OpcSamplingInterval == null ? "default" : configuredNode.OpcSamplingInterval.ToString())}"); OpcNodeOnEndpointModel opcNodeOnEndpoint = new OpcNodeOnEndpointModel(); opcNodeOnEndpoint.Id = configuredNode.Id; opcNodeOnEndpoint.OpcSamplingInterval = configuredNode.OpcSamplingInterval; opcNodeOnEndpoint.OpcPublishingInterval = configuredNode.OpcPublishingInterval; nodesOnEndpoint.Add(opcNodeOnEndpoint); } configEntry.OpcNodes = nodesOnEndpoint; currentConfiguration.Add(configEntry); } // save it on request if (!string.IsNullOrEmpty(_backupFileName) && currentConfiguration.Count > 0) { await File.WriteAllTextAsync(_backupFileName, JsonConvert.SerializeObject(currentConfiguration, Formatting.Indented)); Logger.Information($"The existing OPC Publisher node configuration was saved in '{_backupFileName}'"); } // remove existing configuration on request if (_purgeConfig) { publisher.UnpublishAllConfiguredNodes(ct); Logger.Information($"The existing node configuration was purged. OPC Publisher should no longer publish any data."); } // push new configuration, if required if (_configurationFileEntries != null) { var uniqueEndpoints = _configurationFileEntries.Select(e => e.EndpointUrl).Distinct(); Logger.Information($"The new node configuration will now be set in OPC Publisher."); foreach (var uniqueEndpoint in uniqueEndpoints) { var endpointConfigurationfileEntries = _configurationFileEntries.Where(e => e.EndpointUrl == uniqueEndpoint); List <NodeIdInfo> configurationNodeIdInfos = new List <NodeIdInfo>(); foreach (var endpointConfigurationFileEntry in endpointConfigurationfileEntries) { foreach (var opcNode in endpointConfigurationFileEntry.OpcNodes) { Logger.Debug($"Id '{opcNode.Id}', " + $"OpcPublishingInterval: {(opcNode.OpcPublishingInterval == null ? "default" : opcNode.OpcPublishingInterval.ToString())}, " + $"OpcSamplingInterval: {(opcNode.OpcSamplingInterval == null ? "default" : opcNode.OpcSamplingInterval.ToString())}"); NodeIdInfo nodeIdInfo = new NodeIdInfo(opcNode.Id); configurationNodeIdInfos.Add(nodeIdInfo); } } if (!publisher.PublishNodes(configurationNodeIdInfos, ct, uniqueEndpoint.AbsoluteUri)) { Logger.Error($"Not able to send the new node configuration to OPC Publisher."); } } } // done Logger.Information($"Done. Exiting...."); return; }
/// <summary> /// Returns a list of all published nodes for a specific endpoint in config file format. /// </summary> /// <returns></returns> public List <ConfigurationFileEntryModel> GetPublisherConfigurationFileEntries(string endpointUrl, bool getAll, out uint nodeConfigVersion) { List <ConfigurationFileEntryModel> publisherConfigurationFileEntries = new List <ConfigurationFileEntryModel>(); nodeConfigVersion = (uint)NodeConfigVersion; try { PublisherNodeConfigurationSemaphore.Wait(); try { OpcSessionsListSemaphore.Wait(); // itereate through all sessions, subscriptions and monitored items and create config file entries foreach (var session in OpcSessions) { bool sessionLocked = false; try { sessionLocked = session.LockSessionAsync().Result; if (sessionLocked && (endpointUrl == null || session.EndpointUrl.Equals(endpointUrl, StringComparison.OrdinalIgnoreCase))) { ConfigurationFileEntryModel publisherConfigurationFileEntry = new ConfigurationFileEntryModel(); publisherConfigurationFileEntry.EndpointUrl = new Uri(session.EndpointUrl); publisherConfigurationFileEntry.OpcAuthenticationMode = session.OpcAuthenticationMode; publisherConfigurationFileEntry.EncryptedAuthCredential = session.EncryptedAuthCredential; publisherConfigurationFileEntry.UseSecurity = session.UseSecurity; publisherConfigurationFileEntry.OpcNodes = new List <OpcNodeOnEndpointModel>(); foreach (var subscription in session.OpcSubscriptions) { foreach (var monitoredItem in subscription.OpcMonitoredItems) { // ignore items tagged to stop if (monitoredItem.State != OpcMonitoredItemState.RemovalRequested || getAll == true) { OpcNodeOnEndpointModel opcNodeOnEndpoint = new OpcNodeOnEndpointModel(monitoredItem.OriginalId) { OpcPublishingInterval = subscription.RequestedPublishingIntervalFromConfiguration ? subscription.RequestedPublishingInterval : (int?)null, OpcSamplingInterval = monitoredItem.RequestedSamplingIntervalFromConfiguration ? monitoredItem.RequestedSamplingInterval : (int?)null, DisplayName = monitoredItem.DisplayNameFromConfiguration ? monitoredItem.DisplayName : null, HeartbeatInterval = monitoredItem.HeartbeatIntervalFromConfiguration ? (int?)monitoredItem.HeartbeatInterval : null, SkipFirst = monitoredItem.SkipFirstFromConfiguration ? (bool?)monitoredItem.SkipFirst : null }; publisherConfigurationFileEntry.OpcNodes.Add(opcNodeOnEndpoint); } } } publisherConfigurationFileEntries.Add(publisherConfigurationFileEntry); } } finally { if (sessionLocked) { session.ReleaseSession(); } } } nodeConfigVersion = (uint)NodeConfigVersion; } finally { OpcSessionsListSemaphore.Release(); } } catch (Exception e) { Logger.Error(e, "Reading configuration file entries failed."); publisherConfigurationFileEntries = null; } finally { PublisherNodeConfigurationSemaphore.Release(); } return(publisherConfigurationFileEntries); }