Skip to content

Commit

Permalink
Add feature to use opc-plc as nuget package (#325)
Browse files Browse the repository at this point in the history
* Update nuget

* Use langversion preview

* Add pck icon

* Add nuget config

* Use async wait

* Handle possible null

* Add static dependencies and unpack to output folder

* Cosmetic

* Fix amb. namespace

* Cosmetic

* Incr version

* Cosmetic

* Fix typos and consistency

* Fix typos and consistency

* Sync readme CLI options

* Fix typos

* Simplify namespaces

* Cosmetic

* Add sample files

* Update readme

* Update ver
  • Loading branch information
luiscantero authored Dec 4, 2023
1 parent 0cd1420 commit dd2532c
Show file tree
Hide file tree
Showing 13 changed files with 144 additions and 13 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ products:
urlFragment: azure-iot-sample-opc-ua-server
---


# OPC PLC server
Implements an OPC-UA server with different nodes generating random data, anomalies and configuration of user defined nodes.

Expand Down Expand Up @@ -242,6 +241,13 @@ More information about this feature can be found [here](deterministic-alarms.md)
| StartUpdateSlowNodes | Start the increase of value of slow nodes | slow nodes activated |
| StartUpdateFastNodes | Start the increase of value of fast nodes | fast nodes activated |

## NuGet
- The OPC PLC build generates a NuGet package that can be used to add the OPC PLC server to your own project, e.g. for unit tests
- Sample base class for unit tests: `./samples/OpcPlcBase.cs`
- Sample unit test file that uses the base class: `./samples/OpcUaUnitTests.cs`
- Sample NuGet config to consume a local package (needs to be next to the solution file): `./samples/nuget.config`
- Sample project file that shows how to import the local OPC PLC nuget package: `./samples/OpcUaUnitTests.prj`

## Build
The build scripts are for Azure DevOps and the container build is done in ACR. To use your own ACR you need to:

Expand Down
Binary file added docs/media/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
54 changes: 54 additions & 0 deletions samples/OpcPlcBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
namespace UnitTests;

using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

public class OpcPlcBase
{
public OpcPlcBase(string[] args, int port = 51234)
{
// Passed args override the following defaults.
var serverTask = Task.Run(() => OpcPlc.Program.MainAsync(
args.Concat(
new[]
{
"--autoaccept",
$"--portnum={port}",
"--fn=25",
"--fr=1",
"--ft=uint",
}).ToArray(),
CancellationToken.None)
.GetAwaiter().GetResult());

OpcPlcEndpointUrl = WaitForServerUpAsync(serverTask).GetAwaiter().GetResult();
}

public string OpcPlcEndpointUrl { get; }

private static async Task<string> WaitForServerUpAsync(Task serverTask)
{
while (true)
{
if (serverTask.IsFaulted)
{
throw serverTask.Exception!;
}

if (serverTask.IsCompleted)
{
throw new Exception("Server failed to start.");
}

if (!OpcPlc.Program.Ready)
{
await Task.Delay(1000).ConfigureAwait(false);
continue;
}

return OpcPlc.Program.PlcServer.GetEndpoints()[0].EndpointUrl;
}
}
}
22 changes: 22 additions & 0 deletions samples/OpcUaUnitTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace UnitTests;

using System.Threading.Tasks;

public class OpcUaUnitTests : OpcPlcBase
{
public OpcUaUnitTests()
: base(new[] { "--gn=2" }) // Additional arguments.
{
}

[Test]
public async Task TestConnectedClientSession()
{
var opcUaClient = await OpcUaClientFactory
.GetConnectedClient(OpcPlcEndpointUrl)
.ConfigureAwait(false);

opcUaClient.Session.Connected.Should().BeTrue();
opcUaClient.Session.Close();
}
}
7 changes: 7 additions & 0 deletions samples/OpcUaUnitTests.prj
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<PackageReference Include="Microsoft.IoTEdge.OpcPlc" Version="2.10.0-gdd6f023a37" />
</ItemGroup>

</Project>
8 changes: 8 additions & 0 deletions samples/nuget.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="LocalPackages" value="./packages" />
</packageSources>
</configuration>
8 changes: 8 additions & 0 deletions src/Microsoft.IoTEdge.OpcPlc.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project>
<ItemGroup>
<Files Include="$(MSBuildThisFileDirectory)/../contentFiles/**/*.*" />
</ItemGroup>
<Target Name="CopyFiles" AfterTargets="Build">
<Copy SourceFiles="@(Files)" DestinationFolder="$(TargetDir)/%(RecursiveDir)" />
</Target>
</Project>
6 changes: 3 additions & 3 deletions src/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ private static void InitLogging()
return;
}

LogLevel logLevel = LogLevel.Information;
LogLevel logLevel;

// set the log level
switch (LogLevelCli)
Expand Down Expand Up @@ -402,8 +402,8 @@ public static IHost CreateHostBuilder(string[] args)
}).Build();

return host;
}

}

private static void LogLogo()
{
Logger.LogInformation(
Expand Down
29 changes: 27 additions & 2 deletions src/opc-plc.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,20 @@
<TargetFramework>net8.0</TargetFramework>
<AssemblyName>opcplc</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>OpcPlc</PackageId>
<IsPackable>true</IsPackable>
<PackageId>Microsoft.IoTEdge.OpcPlc</PackageId>
<Authors>Microsoft</Authors>
<Version>1.0.0</Version>
<RootNamespace>OpcPlc</RootNamespace>
<UserSecretsId>bdf7b209-fef3-44d4-9aba-17035fda5efd</UserSecretsId>
<LangVersion>10.0</LangVersion>
<LangVersion>Preview</LangVersion>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Title>Microsoft IoT Edge OPC PLC server</Title>
<Product>Azure Industrial IoT OPC UA PLC Server</Product>
<Description>Implements an OPC-UA server with different nodes generating random data, anomalies and configuration of user defined nodes.</Description>
<RepositoryUrl>https://github.com/Azure-Samples/iot-edge-opc-plc</RepositoryUrl>
<PackageOutputPath>$(OutputPath)</PackageOutputPath>
<PackageIcon>icon.png</PackageIcon>
</PropertyGroup>

<ItemGroup>
Expand Down Expand Up @@ -68,4 +77,20 @@
<Folder Include="AlarmCondition\UnderlyingSystem\" />
</ItemGroup>

<ItemGroup>
<Content Include="Microsoft.IoTEdge.OpcPlc.targets" PackagePath="build/Microsoft.IoTEdge.OpcPlc.targets" />
<Content Include="Boilers/**/*.*" copyToOutput="true">
<PackagePath>contentFiles\Boilers</PackagePath>
</Content>
<Content Include="CompanionSpecs/**/*.*" copyToOutput="true">
<PackagePath>contentFiles\CompanionSpecs</PackagePath>
</Content>
<Content Include="SimpleEvent/**/*.*" copyToOutput="true">
<PackagePath>contentFiles\SimpleEvent</PackagePath>
</Content>
<Content Include="nodesfile.json" copyToOutput="true">
<PackagePath>contentFiles</PackagePath>
</Content>
</ItemGroup>

</Project>
10 changes: 5 additions & 5 deletions tests/PlcSimulatorFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public async Task StartAsync()
_serverCancellationTokenSource.Token)
.GetAwaiter().GetResult());

string endpointUrl = WaitForServerUp();
string endpointUrl = await WaitForServerUpAsync().ConfigureAwait(false);
await _log.WriteAsync($"Found server at: {endpointUrl}").ConfigureAwait(false);

if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
Expand Down Expand Up @@ -284,7 +284,7 @@ private ConfiguredEndpoint GetServerEndpoint(string endpointUrl)
}
}

private string WaitForServerUp()
private async Task<string> WaitForServerUpAsync()
{
while (true)
{
Expand All @@ -295,13 +295,13 @@ private string WaitForServerUp()

if (_serverTask.IsCompleted)
{
throw new Exception("Server failed to start");
throw new Exception("Server failed to start.");
}

if (!Program.Ready)
{
_log.WriteLine("Waiting for server to start...");
Thread.Sleep(1000);
_log.WriteLine("Waiting for server to start ...");
await Task.Delay(1000).ConfigureAwait(false);
continue;
}

Expand Down
2 changes: 1 addition & 1 deletion tests/SimulatorTestsBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public async Task Setup()
[OneTimeTearDown]
public async Task TearDown()
{
Session.Close();
Session?.Close();
await _simulator.StopAsync().ConfigureAwait(false);
}

Expand Down
1 change: 1 addition & 0 deletions tests/opc-plc-tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>OpcPlc.Tests</RootNamespace>
<IsPackable>false</IsPackable>
<LangVersion>Preview</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion version.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
"version": "2.9.15",
"version": "2.10.0",
"versionHeightOffset": -1,
"publicReleaseRefSpec": [
"^refs/heads/main$",
Expand Down

0 comments on commit dd2532c

Please sign in to comment.