-
Notifications
You must be signed in to change notification settings - Fork 0
Dev Add New Provider
This guide describes how to implement a new hardware provider (backend) for the NINA.Plugin.SmartSwitchManager.
The plugin uses a dynamic configuration system powered by the Managed Extensibility Framework (MEF). To add a new provider, you must create a class that implements the ISmartSwitchBackend interface and decorate it with the ExportBackend attribute.
- Create a new C# Class Library project (targeting
net8.0-windows7.0to match N.I.N.A. 3.x). - Add a reference to
NINA.Plugin.SmartSwitchManager.Core.csproj. -
Recommended: Place the project in the
Providers/folder. It will then automatically inherit shared build settings (like N.I.N.A. library versions) from the rootDirectory.Build.props. - Ensure the output DLL is placed in the
Backends/folder of the main plugin directory.
Your class must implement NINA.Plugin.SmartSwitchManager.Core.ISmartSwitchBackend, which inherits from IDisposable.
Decorate the class with ExportBackendAttribute:
-
ProviderId: A unique string ID (e.g., "MyHardware"). -
DisplayName: The name shown in the N.I.N.A. options dropdown. -
SupportsScanning: (Optional) Set totrueif you implement a correspondingISmartSwitchScanner.
[ExportBackend("MyHardware", "My Hardware Brand", SupportsScanning = false)]
public class MyHardwareBackend : ISmartSwitchBackend {
// ...
}Implementation of the ConfigFields property defines the UI elements shown in the N.I.N.A. options.
public IEnumerable<ConfigFieldDescriptor> ConfigFields {
get {
yield return new ConfigFieldDescriptor("Host", "IP/Host", ConfigFieldType.Text, true);
yield return new ConfigFieldDescriptor("Token", "API Token", ConfigFieldType.Password, true);
yield return new ConfigFieldDescriptor("Port", "Port", ConfigFieldType.Number, false, "8080");
// Expert mode field (hidden by default)
yield return new ConfigFieldDescriptor("WebhookId", "Webhook ID", ConfigFieldType.Text) { IsExpertOnly = true };
}
}- Key: The internal name used to store the setting in the dictionary.
- Label: The string displayed in the UI.
-
Type:
Text,Password,Number, orBoolean(renders as aCheckBox). - IsRequired: If true, the field should not be empty. The plugin provides automatic UI validation (red border) for required fields.
- DefaultValue: Optional fallback value.
-
IsExpertOnly: If set to
true, the field is hidden by default. The UI will automatically render an "Expert Mode" toggle switch for the user to reveal these advanced fields.
Called when the backend is instantiated. Use config.GetSetting(key) to retrieve the values defined in ConfigFields.
public void Initialize(SmartSwitchConfig config) {
string host = config.GetSetting("Host");
string token = config.GetSetting("Token");
// Setup your internal HTTP client or connection here
}-
GetStateAsync(): Should returntrueif the switch is ON. -
TurnOnAsync(): Power on the device. -
TurnOffAsync(): Power off the device. -
SetStateAsync(bool targetState, int delaySeconds):- If
delaySeconds == 0, simply callTurnOnorTurnOff. - If
delaySeconds > 0and the hardware supports it, trigger a hardware timer.
- If
-
SupportsHardwareTimer: Returntrueif the hardware supports an automatic "toggle back after X seconds" feature. -
Dispose(): Clean up resources likeHttpClientinstances or timers.
To respect the global timeout setting configured by the user, always use the SmartSwitchHttpClient.GetCts() helper when making network requests:
using var cts = SmartSwitchHttpClient.GetCts();
var response = await httpClient.GetAsync(url, cts.Token);-
Clean Break: Only use the dynamic
GetSettingmethods. Do not add hardcoded properties toSmartSwitchConfig. - Statelessness: The backend instances are created when needed. Store configuration state, but do not rely on long-lived connections unless handled by a singleton.
-
Error Handling: Log errors using
NINA.Core.Utility.Logger. Throw descriptive exceptions duringInitializeif the configuration is invalid. -
MEF Compatibility: Do not use custom objects in the
ExportBackendattribute arguments. Only use strings, bools, and ints. Use theConfigFieldsproperty for complex metadata.
For a faster start, you can copy the fully commented template files from the repository:
- Backend Logic: TemplateBackend.cs
- Network Scanner: TemplateScanner.cs
These files contain detailed explanations for every method and demonstrate how to use all available configuration field types.
using NINA.Plugin.SmartSwitchManager.Core;
using NINA.Plugin.SmartSwitchManager.Core.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace MyNamespace {
[ExportBackend("GenericRest", "Generic REST Switch")]
public class GenericRestBackend : ISmartSwitchBackend {
private string url;
// Dynamic Configuration Fields
public IEnumerable<ConfigFieldDescriptor> ConfigFields {
get {
yield return new ConfigFieldDescriptor("Url", "Endpoint URL", ConfigFieldType.Text, true);
}
}
public bool SupportsHardwareTimer => false;
public void Initialize(SmartSwitchConfig config) {
this.url = config.GetSetting("Url");
}
public async Task<bool> GetStateAsync() {
// Implementation
return true;
}
public async Task TurnOnAsync() => await SetStateAsync(true);
public async Task TurnOffAsync() => await SetStateAsync(false);
public async Task SetStateAsync(bool targetState, int delaySeconds = 0) {
// Implementation
}
}
}