Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3928fe7
Merge pull request #25 from longkerdandy/release/0.9.5
longkerdandy Nov 13, 2025
9d5bf50
Update badge label and bump version to 0.9.7-dev
longkerdandy Nov 13, 2025
e5e8d74
Add option to always subscribe to Sparkplug wildcard topic
longkerdandy Nov 17, 2025
2008f2d
Add profile support and scan rate commands to sample app
longkerdandy Nov 17, 2025
45e3900
Add TCK compatibility results and update profile config
longkerdandy Nov 19, 2025
418acfd
Update README.md
longkerdandy Nov 19, 2025
4f84390
Merge pull request #28 from longkerdandy/feature/tck-compatibility-te…
longkerdandy Nov 19, 2025
5eae1a2
Add edge node/device status tracking service
longkerdandy Nov 30, 2025
31c6afd
Refactor status tracking tests and cache helper
longkerdandy Nov 30, 2025
68f3a92
Add concurrent status update test and improve cache cleanup
longkerdandy Dec 1, 2025
10cb15e
Rename IsOnline to IsEndpointOnline in status service
longkerdandy Dec 1, 2025
ea312db
Add async semaphore to status cache access
longkerdandy Dec 1, 2025
d0d7766
Merge pull request #29 from longkerdandy/feature/edge-node-device-sta…
longkerdandy Dec 1, 2025
3e20e65
Add .trae/ to .gitignore for Trae IDE
longkerdandy Dec 1, 2025
a11c8e3
Add message ordering cache and update related logic
longkerdandy Dec 3, 2025
8eae5c9
Refactor message ordering and status cache services
longkerdandy Dec 3, 2025
c170342
Reorder and update package references in project files
longkerdandy Dec 3, 2025
25fcfec
Rename MessageOrderingCache to MessageOrderingService
longkerdandy Dec 3, 2025
b6cef97
Register cache services and update comment
longkerdandy Dec 3, 2025
a44f853
Merge pull request #30 from longkerdandy/feature/fix-message-ordering
longkerdandy Dec 4, 2025
55f5a05
Update project version to 0.9.7
longkerdandy Dec 11, 2025
5c76bdb
Update README with DI usage and sample improvements
longkerdandy Dec 11, 2025
8f1dff1
Add status tracking option to Sparkplug client
longkerdandy Dec 11, 2025
4727857
Rename Readme.md to MessageOrderingService.md
longkerdandy Dec 11, 2025
d13b853
Rename GIT_FLOW.md to .spec/GIT_FLOW.md
longkerdandy Dec 11, 2025
74507f7
Fix typo in MQTT client log message
longkerdandy Dec 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,7 @@ nunit-*.xml
!.idea/codeStyles/

# VS Code IDE
.vscode/
.vscode/

# Trae IDE
.trae/
File renamed without changes.
90 changes: 65 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![License](https://img.shields.io/github/license/longkerdandy/SparklerNet)](https://github.com/longkerdandy/SparklerNet/blob/main/LICENSE)
[![Language](https://img.shields.io/github/languages/top/longkerdandy/SparklerNet)](https://github.com/longkerdandy/SparklerNet)
[![.NET](https://github.com/longkerdandy/SparklerNet/actions/workflows/dotnet.yml/badge.svg)](https://github.com/longkerdandy/SparklerNet/actions/workflows/dotnet.yml)
[![Build & Test](https://github.com/longkerdandy/SparklerNet/actions/workflows/dotnet.yml/badge.svg)](https://github.com/longkerdandy/SparklerNet/actions/workflows/dotnet.yml)
[![CodeQL Advanced](https://github.com/longkerdandy/SparklerNet/actions/workflows/codeql.yml/badge.svg)](https://github.com/longkerdandy/SparklerNet/actions/workflows/codeql.yml)
[![NuGet Version](https://img.shields.io/nuget/v/SparklerNet)](https://www.nuget.org/packages/SparklerNet/)
[![NuGet Downloads](https://img.shields.io/nuget/dt/SparklerNet)](https://www.nuget.org/packages/SparklerNet/)
Expand Down Expand Up @@ -43,7 +43,7 @@ The library aims to fully implement the complete Sparkplug protocol, with planne
- ✅ Default wildcard topic support (spBv1.0/#)
- ✅ Specific group and edge node subscription support
- ✅ Sparkplug Host Application Message Ordering
- Cache Edge Node and Device birth certificates
- Cache Edge Node and Device online status

### Message Processing

Expand Down Expand Up @@ -73,6 +73,21 @@ The library aims to fully implement the complete Sparkplug protocol, with planne
- ⬜ Reconnection logic with exponential backoff
- ✅ Configuration validation

## Eclipse™ Sparkplug™ TCK Compatibility

The following are the compatibility test results against the Eclipse Sparkplug Test Compatibility Kit (TCK) available at https://github.com/eclipse-sparkplug/sparkplug/tree/master/tck:

### Host Application Tests

| Test | Status |
|------|--------|
| Session Establishment Test | ✅ Passed |
| Session Termination Test | ✅ Passed |
| Send Command Test | ✅ Passed |
| Edge Session Termination Test | ✅ Passed |
| Message Ordering Test | ✅ Passed |
| Multiple MQTT Server (Broker) Test | ❌ Not supported yet |

## Installation

Install SparklerNet via NuGet Package Manager:
Expand All @@ -94,6 +109,15 @@ Or reference it directly in your project:
Here's a simple example of a Sparkplug host application:

```csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using MQTTnet;
using SparklerNet.Core.Constants;
using SparklerNet.Core.Events;
using SparklerNet.HostApplication;
using SparklerNet.HostApplication.Caches;
using SparklerNet.HostApplication.Extensions;

// Create MQTT client options
var mqttOptions = new MqttClientOptionsBuilder()
.WithTcpServer("localhost", 1883)
Expand All @@ -107,15 +131,36 @@ var sparkplugOptions = new SparkplugClientOptions
HostApplicationId = "MyHostApplication"
};

// Create logger
var loggerFactory = LoggerFactory.Create(builder =>
// Create the logger factory
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole();
builder.SetMinimumLevel(LogLevel.Information);
});
var logger = loggerFactory.CreateLogger<SparkplugHostApplication>();

// Create and start host application
var hostApplication = new SparkplugHostApplication(mqttOptions, sparkplugOptions, logger);
// Create the dependency injection container
var services = new ServiceCollection();

// Register the singleton services
services.AddSingleton(mqttOptions);
services.AddSingleton(sparkplugOptions);
services.AddSingleton(loggerFactory);
services.AddSingleton<ILoggerFactory>(loggerFactory);

// Register cache services
services.AddMemoryCache();
services.AddHybridCache();

// Register the SparklerNet services
services.AddSingleton<IMessageOrderingService, MessageOrderingService>();
services.AddSingleton<IStatusTrackingService, StatusTrackingService>();
services.AddSingleton<SparkplugHostApplication>();

// Build service provider
var serviceProvider = services.BuildServiceProvider();

// Resolve SparkplugHostApplication from the container
var hostApplication = serviceProvider.GetRequiredService<SparkplugHostApplication>();

// Subscribe to DBIRTH event
hostApplication.DeviceBirthReceivedAsync += args => {
Expand All @@ -136,17 +181,16 @@ await hostApplication.StopAsync();

## Sample Application

The project includes a comprehensive sample named `SimpleHostApplication` that demonstrates a complete Sparkplug Host Application implementation with the following features:
The project includes a sample named `SimpleHostApplication` demonstrating a complete Sparkplug Host Application implementation with these core features:

- **Interactive Command-Line Interface**: Provides a user-friendly console interface with commands for controlling the application lifecycle and sending commands
- **Complete Event Handling**: Demonstrates subscription and processing of all Sparkplug message types (NBIRTH, NDATA, NDEATH, DBIRTH, DDATA, DDEATH, STATE)
- **Robust Error Handling**: Includes comprehensive exception handling throughout the application lifecycle
- **Advanced Logging System**: Implements structured logging using Serilog, providing detailed information about message reception and processing
- **Command Sending Capabilities**: Allows sending rebirth commands to both Edge Nodes and Devices with customizable parameters
- **User-Friendly Input**: Features command prompts with default values for improved user experience
- **Detailed Data Display**: Shows comprehensive information about received messages including timestamps, sequences, and all metrics with their types and values
- **Interactive CLI**: User-friendly console interface for application lifecycle management and command sending
- **Full Event Processing**: Handles all Sparkplug message types with detailed data display
- **Command Capabilities**: Sends Rebirth and ScanRate commands to Edge Nodes (NCMD) and Devices (DCMD)
- **Configuration Profiles**: Supports multiple profiles (mimic, tck) via `--profile` command line argument
- **Dependency Injection**: Uses Microsoft.Extensions.DependencyInjection for service management
- **Structured Logging**: Implements Serilog for detailed message and processing logging

Please refer to the `SparklerNet.Samples` project for the complete implementation and to see these features in action.
Refer to the `SparklerNet.Samples` project for the complete implementation.

## Project Structure

Expand Down Expand Up @@ -175,6 +219,10 @@ Please refer to the `SparklerNet.Samples` project for the complete implementatio
│ │ └── AssemblyInfo.cs # Assembly information
│ └── SparklerNet.csproj # Core library project file
├── SparklerNet.Samples/ # Sample application
│ ├── Profiles/ # Configuration profiles
│ │ ├── IProfile.cs # Profile interface
│ │ ├── MimicApplicationProfile.cs # Mimic application profile
│ │ └── TCKApplicationProfile.cs # TCK application profile
│ ├── Program.cs # Sample program entry point
│ ├── SimpleHostApplication.cs # Simple host application implementation
│ └── SparklerNet.Samples.csproj # Sample project file
Expand Down Expand Up @@ -208,21 +256,13 @@ SparklerNet supports the following Sparkplug B message types:
## Dependencies

- Google.Protobuf (3.33.0)
- Microsoft.Extensions.Caching.Hybrid (9.10.0)
- Microsoft.Extensions.Caching.Memory (9.0.10)
- Microsoft.Extensions.Logging (9.0.10)
- MQTTnet (5.0.1.1416)
- System.Net.Http (4.3.4)
- System.Text.RegularExpressions (4.3.1)

## Contribution Guidelines

Contributions via Pull Requests and Issues are welcome. Before submitting code, please ensure:

1. Follow the project's code style and [Git Flow](GIT_FLOW.md)
2. Add necessary tests
3. Ensure all tests pass
4. Provide detailed code explanations

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
22 changes: 22 additions & 0 deletions SparklerNet.Samples/Profiles/IProfile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using MQTTnet;
using SparklerNet.Core.Options;

namespace SparklerNet.Samples.Profiles;

/// <summary>
/// This interface defines the contract for a Sparkplug client profile.
/// </summary>
public interface IProfile
{
/// <summary>
/// Gets the MQTT client options for the profile.
/// </summary>
/// <returns>The MQTT client options.</returns>
public MqttClientOptions GetMqttClientOptions();

/// <summary>
/// Gets the Sparkplug client options for the profile.
/// </summary>
/// <returns>The Sparkplug client options.</returns>
public SparkplugClientOptions GetSparkplugClientOptions();
}
36 changes: 36 additions & 0 deletions SparklerNet.Samples/Profiles/MimicApplicationProfile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using MQTTnet;
using MQTTnet.Formatter;
using SparklerNet.Core.Constants;
using SparklerNet.Core.Options;

namespace SparklerNet.Samples.Profiles;

/// <summary>
/// This is a Sparkplug Host Application profile that will subscribe to the MIMIC topic.
/// The MIMIC MQTT Simulators are shared, read-only Sparkplug B sensors publishing unique Sparkplug messages with
/// temperature telemetry to the public brokers TEST.MOSQUITTO.ORG and BROKER.HIVEMQ.COM. For more information about
/// MIMIC MQTT Simulators, visit <a href="https://mqttlab.iotsim.io/sparkplug/">MQTTLAB.IOTSIM.IO/sparkplug</a>
/// </summary>
public class MimicApplicationProfile : IProfile
{
/// <inheritdoc />
public MqttClientOptions GetMqttClientOptions()
{
return new MqttClientOptionsBuilder()
.WithTcpServer("BROKER.HIVEMQ.COM", 1883)
.WithProtocolVersion(MqttProtocolVersion.V311)
.Build();
}

/// <inheritdoc />
public SparkplugClientOptions GetSparkplugClientOptions()
{
return new SparkplugClientOptions
{
Version = SparkplugVersion.V300,
HostApplicationId = "SparklerNetSimpleHostApp",
Subscriptions = { new MqttTopicFilterBuilder().WithTopic("spBv1.0/MIMIC/#").WithAtLeastOnceQoS().Build() },
EnableMessageOrdering = true
};
}
}
36 changes: 36 additions & 0 deletions SparklerNet.Samples/Profiles/TCKApplicationProfile.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using MQTTnet;
using MQTTnet.Formatter;
using SparklerNet.Core.Constants;
using SparklerNet.Core.Options;

namespace SparklerNet.Samples.Profiles;

/// <summary>
/// This is a Sparkplug Host Application profile that will connect to the local MQTT broker for Eclipse™ Sparkplug™ TCK
/// tests. For more information about Eclipse™ Sparkplug™ TCK, visit
/// <a href="https://github.com/eclipse-sparkplug/sparkplug/tree/master/tck">Eclipse™ Sparkplug™ TCK</a>
/// </summary>
public class TckApplicationProfile : IProfile
{
/// <inheritdoc />
public MqttClientOptions GetMqttClientOptions()
{
return new MqttClientOptionsBuilder()
.WithTcpServer("localhost", 1883)
.WithProtocolVersion(MqttProtocolVersion.V500)
.Build();
}

/// <inheritdoc />
public SparkplugClientOptions GetSparkplugClientOptions()
{
return new SparkplugClientOptions
{
Version = SparkplugVersion.V300,
HostApplicationId = "SparklerNetSimpleHostApp",
AlwaysSubscribeToWildcardTopic = true,
EnableMessageOrdering = true,
SeqReorderTimeout = 5000
};
}
}
Loading
Loading