Skip to content

Commit

Permalink
Fix reconnect issues for heartbeat, cyclic read and conditions (#2353)
Browse files Browse the repository at this point in the history
* Documentation updates
* Adding tests for #2351, #2344
* Fix issue where callback is incorrect after reconnecting
* Update dependencies
  • Loading branch information
marcschier authored Oct 6, 2024
1 parent 22d760f commit 93eb89a
Show file tree
Hide file tree
Showing 38 changed files with 407 additions and 138 deletions.
10 changes: 8 additions & 2 deletions docs/opc-publisher/directmethods.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

[Home](./readme.md)

OPC Publisher version 2.8.2 and later implements [IoT Hub Direct Methods](https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-direct-methods), which can be called from an application using the [IoT Hub Device SDK](https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-sdks).
For large-scale deployments, automating the configuration and management of OPC Publisher is critical. OPC Publisher version 2.8.2 and later implements [IoT Hub Direct Methods](https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-direct-methods), which can be called from an application using the [IoT Hub Device SDK](https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-sdks).

The following direct methods are exposed:
Azure IoT Hub's Cloud-to-Device (C2D) commands allow you to remotely configure and control OPC Publisher instances running on IoT Edge devices. For example, you can send commands to update the configuration, restart the module, or change runtime parameters without needing to manually intervene on each device. An example of sending a C2D command to update the configuration:

```bash
az iot hub invoke-module-method --hub-name <your-iot-hub> --device-id <your-device-id> --module-name <opc-publisher> --method-name SetConfiguredEndpoints --method-payload '{"Endpoints": [{"EndpointUrl": "opc.tcp://new-opc-server:4840", "OpcNodes": [{"Id": "ns=2;i=10853"}]}]}'
```

The following direct methods and many more can be used to remotely configure the OPC Publisher:

- [PublishNodes\_V1](#publishnodes_v1)
- [AddOrUpdateEndpoints\_V1](#addorupdateendpoints_v1)
Expand Down
4 changes: 4 additions & 0 deletions docs/opc-publisher/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,10 @@ The simplest way to configure OPC Publisher is via a file. A basic configuration
]
```
This configuration can be placed in a JSON file, typically named publishednodes.json, and provided to OPC Publisher using the [command line](./commandline.md) argument `-f, --pf, --publishfile`, e.g. `--pf=/app/publishednodes.json`.
> Environment variables can also be used to configure OPC Publisher. This method is particularly useful when deploying at scale or in environments where you want to externalize configuration from the container image. An example is `PublishedNodesFile`.
Example configuration files are [here](publishednodes_2.5.json?raw=1) and [here](publishednodes_2.8.json?raw=1).
### Configuration Schema
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" Version="1.12.1" />
<PackageReference Include="Azure.Core" Version="1.43.0" />
<PackageReference Include="Azure.Core" Version="1.44.0" />
<PackageReference Include="Azure.Messaging.EventHubs" Version="5.11.5" />
<PackageReference Include="Azure.ResourceManager.ContainerInstance" Version="1.2.1" />
<PackageReference Include="Azure.ResourceManager.Storage" Version="1.3.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Furly.Extensions.Abstractions" Version="1.0.68" />
<PackageReference Include="Furly.Extensions.Abstractions" Version="1.0.69" />
<PackageReference Include="System.Private.Uri" Version="4.3.2" />
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Furly.Extensions.Json" Version="1.0.68" />
<PackageReference Include="Furly.Extensions.MessagePack" Version="1.0.68" />
<PackageReference Include="Furly.Extensions.Newtonsoft" Version="1.0.68" />
<PackageReference Include="Furly.Extensions.Json" Version="1.0.69" />
<PackageReference Include="Furly.Extensions.MessagePack" Version="1.0.69" />
<PackageReference Include="Furly.Extensions.Newtonsoft" Version="1.0.69" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\src\Azure.IIoT.OpcUa.Publisher.Models.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
<TieredPGO>true</TieredPGO>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Furly.Azure.IoT" Version="1.0.68" />
<PackageReference Include="Furly.Azure.KeyVault" Version="1.0.68" />
<PackageReference Include="Furly.Azure.IoT" Version="1.0.69" />
<PackageReference Include="Furly.Azure.KeyVault" Version="1.0.69" />
<PackageReference Include="System.IO.FileSystem" Version="4.3.0" />
<PackageReference Include="System.Net.Primitives" Version="4.3.1" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@
<None Remove="pki\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Furly.Extensions.AspNetCore" Version="1.0.68" />
<PackageReference Include="Furly.Extensions.Mqtt" Version="1.0.68" />
<PackageReference Include="Furly.Extensions.Dapr" Version="1.0.68" />
<PackageReference Include="Furly.Extensions.MessagePack" Version="1.0.68" />
<PackageReference Include="Furly.Azure.EventHubs" Version="1.0.68" />
<PackageReference Include="Furly.Azure.IoT" Version="1.0.68" />
<PackageReference Include="Furly.Extensions.AspNetCore" Version="1.0.69" />
<PackageReference Include="Furly.Extensions.Mqtt" Version="1.0.69" />
<PackageReference Include="Furly.Extensions.Dapr" Version="1.0.69" />
<PackageReference Include="Furly.Extensions.MessagePack" Version="1.0.69" />
<PackageReference Include="Furly.Azure.EventHubs" Version="1.0.69" />
<PackageReference Include="Furly.Azure.IoT" Version="1.0.69" />
<PackageReference Include="Azure.Identity" Version="1.12.1" />
<PackageReference Include="Azure.Core" Version="1.43.0" />
<PackageReference Include="Furly.Tunnel" Version="1.0.68" />
<PackageReference Include="Azure.Core" Version="1.44.0" />
<PackageReference Include="Furly.Tunnel" Version="1.0.69" />
<PackageReference Include="Mono.Options" Version="6.12.0.148" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<None Remove="Resources\CyclicRead.json" />
<None Remove="Resources\Heartbeat2.json" />
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,15 +310,18 @@ static void Add(List<JsonMessage> messages, JsonElement item, ref JsonMessage? m
/// <param name="arguments"></param>
/// <param name="version"></param>
/// <param name="reverseConnectPort"></param>
/// <param name="keepAliveInterval"></param>
/// <param name="securityMode"></param>
protected void StartPublisher(string test, string publishedNodesFile = null,
string[] arguments = default, MqttVersion? version = null, int? reverseConnectPort = null)
string[] arguments = default, MqttVersion? version = null, int? reverseConnectPort = null,
int keepAliveInterval = 120, SecurityMode? securityMode = null)
{
var sw = Stopwatch.StartNew();
_logger = _logFactory.CreateLogger(test);

arguments ??= Array.Empty<string>();
_publishedNodesFilePath = Path.GetTempFileName();
WritePublishedNodes(test, publishedNodesFile, reverseConnectPort != null);
WritePublishedNodes(test, publishedNodesFile, reverseConnectPort != null, securityMode);

arguments = arguments.Concat(
new[]
Expand All @@ -341,7 +344,7 @@ protected void StartPublisher(string test, string publishedNodesFile = null,
}

_publisher = new PublisherModule(null, null, null, null,
_testOutputHelper, arguments, version);
_testOutputHelper, arguments, version, keepAliveInterval);
_logger.LogInformation("Publisher started in {Elapsed}.", sw.Elapsed);
}

Expand All @@ -351,13 +354,16 @@ protected void StartPublisher(string test, string publishedNodesFile = null,
/// <param name="test"></param>
/// <param name="publishedNodesFile"></param>
/// <param name="useReverseConnect"></param>
protected void WritePublishedNodes(string test, string publishedNodesFile, bool useReverseConnect = false)
/// <param name="securityMode"></param>
protected void WritePublishedNodes(string test, string publishedNodesFile, bool useReverseConnect = false,
SecurityMode? securityMode = null)
{
if (!string.IsNullOrEmpty(publishedNodesFile))
{
File.WriteAllText(_publishedNodesFilePath, File.ReadAllText(publishedNodesFile)
.Replace("\"{{UseReverseConnect}}\"", useReverseConnect ? "true" : "false", StringComparison.Ordinal)
.Replace("{{EndpointUrl}}", EndpointUrl, StringComparison.Ordinal)
.Replace("{{SecurityMode}}", (securityMode ?? SecurityMode.None).ToString(), StringComparison.Ordinal)
.Replace("{{DataSetWriterGroup}}", test, StringComparison.Ordinal));
}
}
Expand Down Expand Up @@ -393,14 +399,16 @@ protected async Task StopPublisherAsync()
/// <param name="test"></param>
/// <param name="publishedNodesFile"></param>
/// <param name="useReverseConnect"></param>
/// <param name="securityMode"></param>
/// <returns></returns>
protected PublishedNodesEntryModel[] GetEndpointsFromFile(string test, string publishedNodesFile,
bool useReverseConnect = false)
bool useReverseConnect = false, SecurityMode? securityMode = null)
{
IJsonSerializer serializer = new NewtonsoftJsonSerializer();
var fileContent = File.ReadAllText(publishedNodesFile)
.Replace("\"{{UseReverseConnect}}\"", useReverseConnect ? "true" : "false", StringComparison.Ordinal)
.Replace("{{EndpointUrl}}", EndpointUrl, StringComparison.Ordinal)
.Replace("{{SecurityMode}}", (securityMode ?? SecurityMode.None).ToString(), StringComparison.Ordinal)
.Replace("{{DataSetWriterGroup}}", test, StringComparison.Ordinal);
return serializer.Deserialize<PublishedNodesEntryModel[]>(fileContent);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,10 @@ public sealed class PublisherModule : WebApplicationFactory<ModuleStartup>, IHtt
/// <param name="testOutputHelper"></param>
/// <param name="arguments"></param>
/// <param name="version"></param>
/// <param name="keepAliveInterval"></param>
public PublisherModule(IMessageSink messageSink, IEnumerable<DeviceTwinModel> devices = null,
string deviceId = null, string moduleId = null, ITestOutputHelper testOutputHelper = null,
string[] arguments = default, MqttVersion? version = null)
string[] arguments = default, MqttVersion? version = null, int keepAliveInterval = 120)
{
_logFactory = testOutputHelper != null ? LogFactory.Create(testOutputHelper, Logging.Config) : null;
ClientContainer = CreateIoTHubSdkClientContainer(messageSink, testOutputHelper, devices, version);
Expand Down Expand Up @@ -163,7 +164,7 @@ public PublisherModule(IMessageSink messageSink, IEnumerable<DeviceTwinModel> de
$"--id={publisherId}",
$"--ec={edgeHubCs}",
$"--mqc={mqttCs}",
"--ki=90",
$"--ki={keepAliveInterval}",
"--aa"
}).ToArray();
if (OperatingSystem.IsLinux())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
"EndpointUrl": "{{EndpointUrl}}",
"UseReverseConnect": "{{UseReverseConnect}}",
"EndpointSecurityMode": "None",
"EndpointSecurityMode": "{{SecurityMode}}",
"DataSetWriterGroup": "{{DataSetWriterGroup}}",
"OpcNodes": [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"EndpointUrl": "{{EndpointUrl}}",
"EndpointSecurityMode": "{{SecurityMode}}",
"DataSetFetchDisplayNames": true,
"OpcNodes": [
{ "Id": "i=2271" },
{ "Id": "i=2254" },
{ "Id": "i=2255" }
]
}
]
Loading

0 comments on commit 93eb89a

Please sign in to comment.