Skip to content

Commit

Permalink
Enable some features by default (#188)
Browse files Browse the repository at this point in the history
* Warn about invalid arguments but continue execution

* Enable some plugin nodes by default

* Show only unknown arguments in warning

* Fix nodeId type

* Enable more features by default

* Update version

* Update readme command line args

* Fix

* Fix

* Cosmetic

* Add comment

* Re-add alarms and events as options

* Fix
  • Loading branch information
luiscantero authored Nov 11, 2022
1 parent f4ae203 commit e2f5f22
Show file tree
Hide file tree
Showing 17 changed files with 190 additions and 196 deletions.
66 changes: 25 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ The tags of the container match the tags of this repository and the containers a

Sample start command for Docker:
~~~
docker run --rm -it -p 50000:50000 -p 8080:8080 --name opcplc mcr.microsoft.com/iotedge/opc-plc:latest --pn=50000 --autoaccept --sph --sn=5 --sr=10 --st=uint --fn=5 --fr=1 --ft=uint --ctb --scn --lid --lsn --ref --gn=5
docker run --rm -it -p 50000:50000 -p 8080:8080 --name opcplc mcr.microsoft.com/iotedge/opc-plc:latest --pn=50000 --autoaccept --sph --sn=5 --sr=10 --st=uint --fn=5 --fr=1 --ft=uint --ref --gn=5
~~~

Sample start command for Windows:
~~~
dotnet opcplc.dll --pn=50000 --at X509Store --autoaccept --sph --sn=5 --sr=10 --st=uint --fn=5 --fr=1 --ft=uint --ctb --scn --lid --lsn --ref --gn=5
dotnet opcplc.dll --pn=50000 --at X509Store --autoaccept --sph --sn=5 --sr=10 --st=uint --fn=5 --fr=1 --ft=uint --ref --gn=5
~~~

Note: Make sure that your OPC UA client uses security policy `Basic256Sha256` and message security mode `Sign & Encrypt` to connect.
Expand Down Expand Up @@ -132,7 +132,7 @@ Additionally, you can set the configuration file name via the option `--spf`.

## Complex type (boiler)

The option `--ctb` adds a simple boiler to the address space.
Adds a simple boiler to the address space.

Features:
- BoilerStatus is a complex type that shows: temperature, pressure and heater state
Expand Down Expand Up @@ -181,16 +181,16 @@ More information about this feature can be found [here](deterministic-alarms.md)

## Other features

- Node with special characters in name and NodeId: `--scn`
- Node with long ID (3950 bytes): `--lid`
- Nodes with large values (10/50 kB string, 100 kB StringArray, 200 kB ByteArray): `--lsn`
- Node with special characters in name and NodeId:
- Node with long ID (3950 bytes)
- Nodes with large values (10/50 kB string, 100 kB StringArray, 200 kB ByteArray)
- Nodes for testing all datatypes, arrays, methods, permissions, etc `--ref`. The ReferenceNodeManager of the [OPC UA .NET reference stack](https://github.com/OPCFoundation/UA-.NETStandard) is used for this purpose.
- Limit the number of updates of Slow and Fast nodes. Update the values of the `SlowNumberOfUpdates` and `FastNumberOfUpdates` configuration nodes in the `OpcPlc/SimulatorConfiguration` folder to:
- `< 0` (default): Slow and Fast nodes are updated indefinitely
- `0`: Slow and Fast nodes are not updated
- `> 0`: Slow and Fast nodes are updated the given number of times, then they stop being updated (the value of the configuration node is decremented at every update).
- Nodes with deterministic random GUIDs as node IDs: `--gn=<number_of_nodes>`
- Node with opaque identifier (free-format byte string): `--on`
- Node with opaque identifier (free-format byte string)

## OPC UA Methods

Expand Down Expand Up @@ -280,10 +280,10 @@ Options:
endpoint.
Default: ''
--ph, --plchostname=VALUE
the fullqualified hostname of the plc.
the fully-qualified hostname of the PLC.
Default: machinename
--ol, --opcmaxstringlen=VALUE
the max length of a string opc can transmit/
the max length of a string OPC can transmit/
receive.
Default: 4194304
--lr, --ldsreginterval=VALUE
Expand All @@ -308,23 +308,23 @@ Options:
stored
Default (depends on store type):
X509Store: 'CurrentUser\UA_MachineDefault'
Directory: 'pki/own'
Directory: 'pki\own'
--tp, --trustedcertstorepath=VALUE
the path of the trusted cert store
Default 'pki/trusted'
Default 'pki\trusted'
--rp, --rejectedcertstorepath=VALUE
the path of the rejected cert store
Default 'pki/rejected'
Default 'pki\rejected'
--ip, --issuercertstorepath=VALUE
the path of the trusted issuer cert store
Default 'pki/issuer'
Default 'pki\issuer'
--csr show data to create a certificate signing request
Default 'False'
--ab, --applicationcertbase64=VALUE
update/set this applications certificate with the
update/set this application's certificate with the
certificate passed in as bas64 string
--af, --applicationcertfile=VALUE
update/set this applications certificate with the
update/set this application's certificate with the
certificate file specified
--pb, --privatekeybase64=VALUE
initial provisioning of the application
Expand All @@ -338,20 +338,20 @@ Options:
the optional password for the PEM or PFX or the
installed application certificate
--tb, --addtrustedcertbase64=VALUE
adds the certificate to the applications trusted
adds the certificate to the application's trusted
cert store passed in as base64 string (comma
separated values)
--tf, --addtrustedcertfile=VALUE
adds the certificate file(s) to the applications
adds the certificate file(s) to the application's
trusted cert store passed in as base64 string (
multiple filenames supported)
--ib, --addissuercertbase64=VALUE
adds the specified issuer certificate to the
applications trusted issuer cert store passed in
as base64 string (comma separated values)
application's trusted issuer cert store passed
in as base64 string (comma separated values)
--if, --addissuercertfile=VALUE
adds the specified issuer certificate file(s) to
the applications trusted issuer cert store (
the application's trusted issuer cert store (
multiple filenames supported)
--rb, --updatecrlbase64=VALUE
update the CRL passed in as base64 string to the
Expand All @@ -362,8 +362,8 @@ Options:
corresponding cert store (trusted or trusted
issuer)
--rc, --removecert=VALUE
remove cert(s) with the given thumbprint(s) (
comma separated values)
remove cert(s) with the given thumbprint(s) (comma
separated values)
--daa, --disableanonymousauth
flag to disable anonymous authentication.
Default: False
Expand All @@ -389,9 +389,6 @@ Options:
Default: False
--ses, --simpleevents add simple events simulation to address space.
Default: False
--ref, --referencetest add reference test simulation node manager to
address space.
Default: False
--dalm, --deterministicalarms=VALUE
add deterministic alarm simulation to address
space.
Expand All @@ -412,11 +409,9 @@ Options:
Default: 8080
--cdn, --certdnsnames=VALUE
add additional DNS names or IP addresses to this
application's certificate (comma separated values)
application's certificate (comma separated
values)
-h, --help show this message and exit
--ctb, --complextypeboiler
add complex type (boiler) to address space.
Default: False
--nv, --nodatavalues do not generate data values
Default: False
--gn, --guidnodes=VALUE
Expand Down Expand Up @@ -453,17 +448,9 @@ Options:
Default: 0
--vfr, --veryfastrate=VALUE
rate in milliseconds to change fast nodes
Default: 10000
--lid, --longid add node with ID of 3950 chars.
Default: False
--lsn, --longstringnodes
add nodes with string values of 10/50/100/200 kB.
Default: False
Default: 1000
--nn, --nonegtrend do not generate negative trend data
Default: False
--on, --opaquenode
add node with an opaque identifier
Default: False
--np, --nopostrend do not generate positive trend data
Default: False
--sn, --slownodes=VALUE
Expand Down Expand Up @@ -493,9 +480,6 @@ Options:
--ssi, --slownodesamplinginterval=VALUE
rate in milliseconds to sample slow nodes
Default: 0
--scn, --specialcharname
add node with special characters in name
Default: False
--ns, --nospikes do not generate spike data
Default: False
--nf, --nodesfile=VALUE
Expand Down
1 change: 0 additions & 1 deletion src/CliOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,6 @@ public static Mono.Options.OptionSet InitCommandLineOptions()
// Special nodes
{ "alm|alarms", $"add alarm simulation to address space.\nDefault: {AddAlarmSimulation}", (string s) => AddAlarmSimulation = s != null },
{ "ses|simpleevents", $"add simple events simulation to address space.\nDefault: {AddSimpleEventsSimulation}", (string s) => AddSimpleEventsSimulation = s != null },
{ "ref|referencetest", $"add reference test simulation node manager to address space.\nDefault: {AddReferenceTestSimulation}", (string s) => AddReferenceTestSimulation = s != null },
{ "dalm|deterministicalarms=", $"add deterministic alarm simulation to address space.\nProvide a script file for controlling deterministic alarms.", (string s) => DeterministicAlarmSimulationFile = s },

// misc
Expand Down
11 changes: 10 additions & 1 deletion src/PlcSimulation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,18 @@ public class PlcSimulation
/// <summary>
/// Flags for node generation.
/// </summary>

// alm|alarms
// add alarm simulation to address space.
public static bool AddAlarmSimulation { get; set; }

// ses|simpleevents
// Add simple events simulation to address space.
public static bool AddSimpleEventsSimulation { get; set; }
public static bool AddReferenceTestSimulation { get; set; }

// ref|referencetest
// Add reference test simulation node manager to address space.
public static bool AddReferenceTestSimulation { get; set; } = true;
public static string DeterministicAlarmSimulationFile { get; set; }

public static uint EventInstanceCount { get; set; } = 0;
Expand Down
7 changes: 3 additions & 4 deletions src/PluginNodes/ComplexTypeBoilerPluginNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ public class ComplexTypeBoilerPluginNode : IPluginNodes

public void AddOptions(Mono.Options.OptionSet optionSet)
{
optionSet.Add(
"ctb|complextypeboiler",
$"add complex type (boiler) to address space.\nDefault: {_isEnabled}",
(string s) => _isEnabled = s != null);
// ctb|complextypeboiler
// Add complex type (boiler) to address space.
_isEnabled = true;
}

public void AddToAddressSpace(FolderState telemetryFolder, FolderState methodsFolder, PlcNodeManager plcNodeManager)
Expand Down
7 changes: 3 additions & 4 deletions src/PluginNodes/LongIdPluginNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ public class LongIdPluginNode : IPluginNodes

public void AddOptions(Mono.Options.OptionSet optionSet)
{
optionSet.Add(
"lid|longid",
$"add node with ID of 3950 chars.\nDefault: {_isEnabled}",
(string s) => _isEnabled = s != null);
// lid|longid
// Add node with ID of 3950 chars.
_isEnabled = true;
}

public void AddToAddressSpace(FolderState telemetryFolder, FolderState methodsFolder, PlcNodeManager plcNodeManager)
Expand Down
7 changes: 3 additions & 4 deletions src/PluginNodes/LongStringPluginNodes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ public class LongStringPluginNodes : IPluginNodes

public void AddOptions(Mono.Options.OptionSet optionSet)
{
optionSet.Add(
"lsn|longstringnodes",
$"add nodes with string values of 10/50/100/200 kB.\nDefault: {_isEnabled}",
(string s) => _isEnabled = s != null);
// lsn|longstringnodes
// Add nodes with string values of 10/50/100/200 kB.
_isEnabled = true;
}

public void AddToAddressSpace(FolderState telemetryFolder, FolderState methodsFolder, PlcNodeManager plcNodeManager)
Expand Down
7 changes: 3 additions & 4 deletions src/PluginNodes/OpaquePluginNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ public class OpaquePluginNode : IPluginNodes

public void AddOptions(Mono.Options.OptionSet optionSet)
{
optionSet.Add(
"on|opaquenode",
$"add node with an opaque identifier.\nDefault: {_isEnabled}",
(string s) => _isEnabled = s != null);
// on|opaquenode
// Add node with an opaque identifier.
_isEnabled = true;
}

public void AddToAddressSpace(FolderState telemetryFolder, FolderState methodsFolder, PlcNodeManager plcNodeManager)
Expand Down
7 changes: 3 additions & 4 deletions src/PluginNodes/SpecialCharNamePluginNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ public class SpecialCharNamePluginNode : IPluginNodes

public void AddOptions(Mono.Options.OptionSet optionSet)
{
optionSet.Add(
"scn|specialcharname",
$"add node with special characters in name.\nDefault: {_isEnabled}",
(string s) => _isEnabled = s != null);
// scn|specialcharname
// Add node with special characters in name.
_isEnabled = true;
}

public void AddToAddressSpace(FolderState telemetryFolder, FolderState methodsFolder, PlcNodeManager plcNodeManager)
Expand Down
14 changes: 9 additions & 5 deletions src/PluginNodes/UserDefinedPluginNodes.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
namespace OpcPlc.PluginNodes;

using Newtonsoft.Json;
using Opc.Ua;
using OpcPlc.Helpers;
using OpcPlc.PluginNodes.Models;
using System;
using System.Collections.Generic;
using System.IO;
using static OpcPlc.Program;
using Newtonsoft.Json;
using OpcPlc.PluginNodes.Models;
using OpcPlc.Helpers;

/// <summary>
/// Nodes that are configuration via JSON file.
Expand Down Expand Up @@ -90,10 +90,14 @@ private void AddNodes(FolderState folder)
node.Description = node.Name;
}

Logger.Debug($"Create node with Id '{typedNodeId}' and BrowseName '{node.Name}' in namespace with index '{_plcNodeManager.NamespaceIndexes[(int)NamespaceType.OpcPlcApplications]}'");
Logger.Debug("Create node with Id {typedNodeId} and BrowseName {name} in namespace with index {namespaceIndex}",
typedNodeId,
node.Name,
_plcNodeManager.NamespaceIndexes[(int)NamespaceType.OpcPlcApplications]);

CreateBaseVariable(userNodesFolder, node);

nodes.Add(PluginNodesHelpers.GetNodeWithIntervals(node.NodeId, _plcNodeManager));
nodes.Add(PluginNodesHelpers.GetNodeWithIntervals((NodeId)node.NodeId, _plcNodeManager));
}

Logger.Information("Completed processing user defined node information");
Expand Down
3 changes: 1 addition & 2 deletions src/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,8 @@ public static async Task MainAsync(string[] args, CancellationToken cancellation
// Validate and parse extra arguments
if (extraArgs.Count > 0)
{
Logger.Error($"Error with command line arguments: {string.Join(" ", args)}");
Logger.Warning($"Found one or more invalid command line arguments: {string.Join(" ", extraArgs)}");
CliOptions.PrintUsage(options);
return;
}

LogLogo();
Expand Down
14 changes: 7 additions & 7 deletions tests/DeterministicAlarmsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public void FiresEventSequence()
NodeShouldHaveStates(lightOff2, Inactive, Disabled);

var waitUntilStartInSeconds = FromSeconds(9); // value in dalm001.json file
FireTimersWithPeriodAndReceiveEvents(waitUntilStartInSeconds, 1)
FireTimersWithPeriodAndReceiveEvents(waitUntilStartInSeconds, expectedCount: 1)
.First()
.Should().Contain(new Dictionary<string, object>
{
Expand All @@ -67,7 +67,7 @@ public void FiresEventSequence()

AdvanceToNextStep();

FireTimersWithPeriodAndReceiveEvents(FromSeconds(5), 1)
FireTimersWithPeriodAndReceiveEvents(FromSeconds(5), expectedCount: 1)
.First()
.Should().Contain(new Dictionary<string, object>
{
Expand All @@ -83,7 +83,7 @@ public void FiresEventSequence()

AdvanceToNextStep();

FireTimersWithPeriodAndReceiveEvents(FromSeconds(7), 1)
FireTimersWithPeriodAndReceiveEvents(FromSeconds(7), expectedCount: 1)
.First()
.Should().Contain(new Dictionary<string, object>
{
Expand All @@ -99,7 +99,7 @@ public void FiresEventSequence()

AdvanceToNextStep();

FireTimersWithPeriodAndReceiveEvents(FromSeconds(4), 1)
FireTimersWithPeriodAndReceiveEvents(FromSeconds(4), expectedCount: 1)
.First()
.Should().Contain(new Dictionary<string, object>
{
Expand All @@ -113,7 +113,7 @@ public void FiresEventSequence()

NodeShouldHaveStates(tempHigh1, Active, Enabled);

FireTimersWithPeriodAndReceiveEvents(FromMilliseconds(1), 1)
FireTimersWithPeriodAndReceiveEvents(FromMilliseconds(1), expectedCount: 1)
.First()
.Should().Contain(new Dictionary<string, object>
{
Expand All @@ -125,7 +125,7 @@ public void FiresEventSequence()

AdvanceToNextStep();

FireTimersWithPeriodAndReceiveEvents(FromSeconds(5), 1)
FireTimersWithPeriodAndReceiveEvents(FromSeconds(5), expectedCount: 1)
.First()
.Should().Contain(new Dictionary<string, object>
{
Expand All @@ -138,7 +138,7 @@ public void FiresEventSequence()
AdvanceToNextStep();

// At this point, the *runningForSeconds* limit in the JSON file causes execution to stop
FireTimersWithPeriodAndReceiveEvents(FromSeconds(1), 0);
FireTimersWithPeriodAndReceiveEvents(FromSeconds(1), expectedCount: 0);

NodeShouldHaveStates(doorOpen1, Active, Enabled);
NodeShouldHaveStates(tempHigh1, Active, Enabled);
Expand Down
Loading

0 comments on commit e2f5f22

Please sign in to comment.