diff --git a/src/PVOutput.Net/Modules/NotificationService.cs b/src/PVOutput.Net/Modules/NotificationService.cs
new file mode 100644
index 0000000..9b9c67d
--- /dev/null
+++ b/src/PVOutput.Net/Modules/NotificationService.cs
@@ -0,0 +1,182 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Dawn;
+using PVOutput.Net.Builders;
+using PVOutput.Net.Objects;
+using PVOutput.Net.Objects.Core;
+using PVOutput.Net.Requests.Handler;
+using PVOutput.Net.Requests.Modules;
+using PVOutput.Net.Responses;
+
+namespace PVOutput.Net.Modules
+{
+ ///
+ /// The Notification service enables (de-)registering alert notifications.
+ /// See the official API information.
+ ///
+ public sealed class NotificationService : BaseService
+ {
+ ///
+ /// Alert for a new private message.
+ ///
+ public const int PrivateMessageAlert = 1;
+
+ ///
+ /// Alert for joining a new team.
+ ///
+ public const int JoinedTeamAlert = 3;
+
+ ///
+ /// Alert for an added favourite.
+ ///
+ public const int AddedFavouriteAlert = 4;
+
+ ///
+ /// Alert for high consumption.
+ ///
+ public const int HighConsumptionAlert = 5;
+
+ ///
+ /// Alert for an idle system.
+ ///
+ public const int SystemIdleAlert = 6;
+
+ ///
+ /// Alert for low generation.
+ ///
+ public const int LowGenerationAlert = 8;
+
+ ///
+ /// Alert for low performance.
+ ///
+ public const int PerformanceAlert = 11;
+
+ ///
+ /// Alerty for a high standby cost alert.
+ ///
+ public const int StandbyCostAlert = 14;
+
+ ///
+ /// Alert for extended data element 7.
+ ///
+ public const int ExtendedDataV7Alert = 15;
+
+ ///
+ /// Alert for extended data element 8.
+ ///
+ public const int ExtendedDataV8Alert = 16;
+
+ ///
+ /// Alert for extended data element 9.
+ ///
+ public const int ExtendedDataV9Alert = 17;
+
+ ///
+ /// Alert for extended data element 10.
+ ///
+ public const int ExtendedDataV10Alert = 18;
+
+ ///
+ /// Alert for extended data element 11.
+ ///
+ public const int ExtendedDataV11Alert = 19;
+
+ ///
+ /// Alert for extended data element 12.
+ ///
+ public const int ExtendedDataV12Alert = 20;
+
+ ///
+ /// Alert for high net power.
+ ///
+ public const int HighNetPowerAlert = 23;
+
+ ///
+ /// Alert for low net power.
+ ///
+ public const int LowNetPowerAlert = 24;
+
+ internal NotificationService(PVOutputClient client) : base(client)
+ {
+ }
+
+ ///
+ /// Registers an application for a notification.
+ ///
+ /// ApplicationId to register the notification under.
+ /// The url that should get called for each notification.
+ /// A specific type of alert to send, leave empty for all alert types.
+ /// A cancellation token for the request.
+ /// If the operation succeeded.
+ public Task RegisterNotificationAsync(string applicationId, string callbackUrl, int? alertType = null, CancellationToken cancellationToken = default)
+ {
+ var loggingScope = new Dictionary()
+ {
+ [LoggingEvents.RequestId] = LoggingEvents.NotificationService_RegisterNotification,
+ [LoggingEvents.Parameter_ApplicationId] = applicationId,
+ [LoggingEvents.Parameter_CallBackUrl] = callbackUrl,
+ [LoggingEvents.Parameter_AlertType] = alertType
+
+ };
+
+ Guard.Argument(applicationId, nameof(applicationId)).MaxLength(100).NotEmpty();
+ Guard.Argument(callbackUrl, nameof(callbackUrl)).MaxLength(150).NotEmpty();
+
+ var handler = new RequestHandler(Client);
+ return handler.ExecutePostRequestAsync(new RegisterNotificationRequest() { ApplicationId = applicationId, CallbackUri = new Uri(callbackUrl), AlertType = alertType }, loggingScope, cancellationToken);
+ }
+
+
+ ///
+ /// Registers an application for a notification.
+ ///
+ /// ApplicationId to register the notification under.
+ /// The uri that should get called for each notification.
+ /// A specific type of alert to send, leave empty for all alert types.
+ /// A cancellation token for the request.
+ /// If the operation succeeded.
+ public Task RegisterNotificationAsync(string applicationId, Uri callbackUri, int? alertType = null, CancellationToken cancellationToken = default)
+ {
+ var loggingScope = new Dictionary()
+ {
+ [LoggingEvents.RequestId] = LoggingEvents.NotificationService_RegisterNotification,
+ [LoggingEvents.Parameter_ApplicationId] = applicationId,
+ [LoggingEvents.Parameter_CallBackUrl] = callbackUri.AbsoluteUri,
+ [LoggingEvents.Parameter_AlertType] = alertType
+
+ };
+
+ Guard.Argument(applicationId, nameof(applicationId)).MaxLength(100).NotEmpty();
+ Guard.Argument(callbackUri, nameof(callbackUri)).NotNull();
+ Guard.Argument(callbackUri.AbsoluteUri, nameof(callbackUri)).MaxLength(150).NotEmpty();
+
+ var handler = new RequestHandler(Client);
+ return handler.ExecutePostRequestAsync(new RegisterNotificationRequest() { ApplicationId = applicationId, CallbackUri = callbackUri, AlertType = alertType }, loggingScope, cancellationToken);
+ }
+
+ ///
+ /// Deregisters an application for a notification.
+ ///
+ /// ApplicationId to register the notification under.
+ /// A specific type of alert to send, leave empty for all alert types.
+ /// A cancellation token for the request.
+ /// If the operation succeeded.
+ public Task DeregisterNotificationAsync(string applicationId, int? alertType = null, CancellationToken cancellationToken = default)
+ {
+ var loggingScope = new Dictionary()
+ {
+ [LoggingEvents.RequestId] = LoggingEvents.NotificationService_DeregisterNotification,
+ [LoggingEvents.Parameter_ApplicationId] = applicationId,
+ [LoggingEvents.Parameter_AlertType] = alertType
+ };
+
+ Guard.Argument(applicationId, nameof(applicationId)).MaxLength(100);
+
+ var handler = new RequestHandler(Client);
+ return handler.ExecutePostRequestAsync(new DeregisterNotificationRequest { ApplicationId = applicationId, AlertType = alertType }, loggingScope, cancellationToken);
+ }
+ }
+}
diff --git a/src/PVOutput.Net/Objects/Core/BaseObjectStringReader.cs b/src/PVOutput.Net/Objects/Core/BaseObjectStringReader.cs
index 4fa66cd..806e73b 100644
--- a/src/PVOutput.Net/Objects/Core/BaseObjectStringReader.cs
+++ b/src/PVOutput.Net/Objects/Core/BaseObjectStringReader.cs
@@ -43,7 +43,7 @@ public async Task ReadObjectAsync(TextReader reader, CancellationTo
if (reader != null && reader.Peek() >= 0)
{
TReturnType output = CreateObjectInstance();
- ParseProperties(output, reader);
+ ParseProperties(output, reader, cancellationToken);
return output;
}
diff --git a/src/PVOutput.Net/Objects/Core/LoggingEvents.cs b/src/PVOutput.Net/Objects/Core/LoggingEvents.cs
index 1d6e045..e22f271 100644
--- a/src/PVOutput.Net/Objects/Core/LoggingEvents.cs
+++ b/src/PVOutput.Net/Objects/Core/LoggingEvents.cs
@@ -39,6 +39,9 @@ internal class LoggingEvents
public const string Parameter_Search_TeamName = "Teamname";
public const string Parameter_Search_Orientation = "Orientation";
public const string Parameter_Search_Tilt = "Tilt";
+ public const string Parameter_ApplicationId = "ApplicationId";
+ public const string Parameter_CallBackUrl = "CallBackUrl";
+ public const string Parameter_AlertType = "AlertType";
/*
* RequestHandler base events
@@ -92,5 +95,7 @@ internal class LoggingEvents
public static readonly EventId TeamService_GetTeam = new EventId(21101, "GetTeam");
public static readonly EventId TeamService_JoinTeam = new EventId(21102, "JoinTeam");
public static readonly EventId TeamService_LeaveTeam = new EventId(21103, "LeaveTeam");
+ public static readonly EventId NotificationService_RegisterNotification = new EventId(21201, "RegisterNotification");
+ public static readonly EventId NotificationService_DeregisterNotification = new EventId(21202, "DeregisterNotification");
}
}
diff --git a/src/PVOutput.Net/PVOutput.Net.csproj b/src/PVOutput.Net/PVOutput.Net.csproj
index 926f82e..d3d81f8 100644
--- a/src/PVOutput.Net/PVOutput.Net.csproj
+++ b/src/PVOutput.Net/PVOutput.Net.csproj
@@ -38,13 +38,13 @@ https://github.com/pyrocumulus/pvoutput.net/blob/master/CHANGELOG.md
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
diff --git a/src/PVOutput.Net/PVOutputClient.cs b/src/PVOutput.Net/PVOutputClient.cs
index 65d848b..a35b339 100644
--- a/src/PVOutput.Net/PVOutputClient.cs
+++ b/src/PVOutput.Net/PVOutputClient.cs
@@ -116,6 +116,12 @@ internal ILogger Logger
///
public SearchService Search { get; private set; }
+ ///
+ /// The notification service
+ /// See the official API information.
+ ///
+ public NotificationService Notification { get; private set; }
+
///
/// Creates a new PVOutputClient.
///
@@ -177,6 +183,7 @@ private void CreateServices()
Insolation = new InsolationService(this);
Supply = new SupplyService(this);
Search = new SearchService(this);
+ Notification = new NotificationService(this);
}
}
}
diff --git a/src/PVOutput.Net/Requests/Modules/DeregisterNotificationRequest.cs b/src/PVOutput.Net/Requests/Modules/DeregisterNotificationRequest.cs
new file mode 100644
index 0000000..5afc3c1
--- /dev/null
+++ b/src/PVOutput.Net/Requests/Modules/DeregisterNotificationRequest.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+using System.Net.Http;
+using PVOutput.Net.Requests.Base;
+
+namespace PVOutput.Net.Requests.Modules
+{
+ internal class DeregisterNotificationRequest : PostRequest
+ {
+ public string ApplicationId { get; set; }
+ public int? AlertType { get; set; }
+
+ public override HttpMethod Method => HttpMethod.Post;
+
+ public override string UriTemplate => "deregisternotification.jsp{?appid,type}";
+
+ public override IDictionary GetUriPathParameters()
+ {
+ return new Dictionary
+ {
+ ["appid"] = ApplicationId,
+ ["type"] = AlertType ?? 0
+ };
+ }
+ }
+}
diff --git a/src/PVOutput.Net/Requests/Modules/OutputRequest.cs b/src/PVOutput.Net/Requests/Modules/OutputRequest.cs
index 5cb4b5a..0aa7ceb 100644
--- a/src/PVOutput.Net/Requests/Modules/OutputRequest.cs
+++ b/src/PVOutput.Net/Requests/Modules/OutputRequest.cs
@@ -31,7 +31,7 @@ internal class OutputRequest : GetRequest
["insolation"] = Insolation ? 1 : 0
};
- private string GetAggregationParameter(AggregationPeriod? aggregationPeriod)
+ private static string GetAggregationParameter(AggregationPeriod? aggregationPeriod)
{
if (aggregationPeriod == null)
{
diff --git a/src/PVOutput.Net/Requests/Modules/RegisterNotificationRequest.cs b/src/PVOutput.Net/Requests/Modules/RegisterNotificationRequest.cs
new file mode 100644
index 0000000..2b441e5
--- /dev/null
+++ b/src/PVOutput.Net/Requests/Modules/RegisterNotificationRequest.cs
@@ -0,0 +1,27 @@
+using System.Collections.Generic;
+using System.Net.Http;
+using PVOutput.Net.Requests.Base;
+
+namespace PVOutput.Net.Requests.Modules
+{
+ internal class RegisterNotificationRequest : PostRequest
+ {
+ public string ApplicationId { get; set; }
+ public System.Uri CallbackUri { get; set; }
+ public int? AlertType { get; set; }
+
+ public override HttpMethod Method => HttpMethod.Post;
+
+ public override string UriTemplate => "registernotification.jsp{?appid,url,type}";
+
+ public override IDictionary GetUriPathParameters()
+ {
+ return new Dictionary
+ {
+ ["appid"] = ApplicationId,
+ ["url"] = CallbackUri?.AbsoluteUri ?? "",
+ ["type"] = AlertType ?? 0
+ };
+ }
+ }
+}
diff --git a/tests/PVOutput.Net.Tests/Modules/Notification/NotificationServiceTests.cs b/tests/PVOutput.Net.Tests/Modules/Notification/NotificationServiceTests.cs
new file mode 100644
index 0000000..295e016
--- /dev/null
+++ b/tests/PVOutput.Net.Tests/Modules/Notification/NotificationServiceTests.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using NUnit.Framework;
+using PVOutput.Net.Objects;
+using PVOutput.Net.Requests.Modules;
+using PVOutput.Net.Tests.Utils;
+using RichardSzalay.MockHttp;
+
+namespace PVOutput.Net.Tests.Modules.Supply
+{
+ [TestFixture]
+ public partial class NotificationServiceTests : BaseRequestsTest
+ {
+ [Test]
+ public void Parameter_ApplicationId_CreatesCorrectUriParameters()
+ {
+ var request = new RegisterNotificationRequest() { ApplicationId = "my.first.application" };
+ var parameters = request.GetUriPathParameters();
+ Assert.That(parameters["appid"], Is.EqualTo("my.first.application"));
+ }
+
+ [Test]
+ public void Parameter_CallbackUrl_CreatesCorrectUriParameters()
+ {
+ var request = new RegisterNotificationRequest() { CallbackUri = new Uri("http://www.google.com/callmeback") };
+ var parameters = request.GetUriPathParameters();
+ Assert.That(parameters["url"], Is.EqualTo("http://www.google.com/callmeback"));
+ }
+
+ [Test]
+ public void Parameter_AlertType_CreatesCorrectUriParameters()
+ {
+ var request = new RegisterNotificationRequest() { AlertType = 11 };
+ var parameters = request.GetUriPathParameters();
+ Assert.That(parameters["type"], Is.EqualTo(11));
+ }
+
+ [Test]
+ public void Parameter_ApplicationId_Deregister_CreatesCorrectUriParameters()
+ {
+ var request = new DeregisterNotificationRequest() { ApplicationId = "my.first.application" };
+ var parameters = request.GetUriPathParameters();
+ Assert.That(parameters["appid"], Is.EqualTo("my.first.application"));
+ }
+
+ [Test]
+ public void Parameter_AlertType_Deregister_CreatesCorrectUriParameters()
+ {
+ var request = new DeregisterNotificationRequest() { AlertType = 11 };
+ var parameters = request.GetUriPathParameters();
+ Assert.That(parameters["type"], Is.EqualTo(11));
+ }
+
+
+ [Test]
+ public async Task NotificationService_RegisterNotification_CallsCorrectUri()
+ {
+ PVOutputClient client = TestUtility.GetMockClient(out MockHttpMessageHandler testProvider);
+
+ testProvider.ExpectUriFromBase(REGISTERNOTIFICATION_URL)
+ .WithQueryString("appid=my.application.id&type=14&url=http://www.google.com/callmeback")
+ .RespondPlainText("");
+
+ var response = await client.Notification.RegisterNotificationAsync("my.application.id", "http://www.google.com/callmeback", 14);
+ testProvider.VerifyNoOutstandingExpectation();
+ AssertStandardResponse(response);
+ }
+
+ [Test]
+ public async Task NotificationService_RegisterNotificationViaUri_CallsCorrectUri()
+ {
+ PVOutputClient client = TestUtility.GetMockClient(out MockHttpMessageHandler testProvider);
+
+ testProvider.ExpectUriFromBase(REGISTERNOTIFICATION_URL)
+ .WithQueryString("appid=my.application.id&type=17&url=http://www.microsoft.com/callmeback")
+ .RespondPlainText("");
+
+ var response = await client.Notification.RegisterNotificationAsync("my.application.id", new Uri("http://www.microsoft.com/callmeback"), 17);
+ testProvider.VerifyNoOutstandingExpectation();
+ AssertStandardResponse(response);
+ }
+
+ [Test]
+ public async Task NotificationService_DeregisterNotification_CallsCorrectUri()
+ {
+ PVOutputClient client = TestUtility.GetMockClient(out MockHttpMessageHandler testProvider);
+
+ testProvider.ExpectUriFromBase(DEREGISTERNOTIFICATION_URL)
+ .WithQueryString("appid=my.application.id&type=24")
+ .RespondPlainText("");
+
+ var response = await client.Notification.DeregisterNotificationAsync("my.application.id", 24);
+ testProvider.VerifyNoOutstandingExpectation();
+ AssertStandardResponse(response);
+ }
+
+ [Test]
+ public void ApplicationId_TooLong_Throws()
+ {
+ PVOutputClient client = TestUtility.GetMockClient(out MockHttpMessageHandler testProvider);
+
+ testProvider.ExpectUriFromBase(REGISTERNOTIFICATION_URL)
+ .RespondPlainText("");
+
+ var exception = Assert.ThrowsAsync(async () =>
+ {
+ _ = await client.Notification.RegisterNotificationAsync(new string('*', 101), "");
+ });
+ }
+
+
+ [Test]
+ public void CallbackUrl_TooLong_Throws()
+ {
+ PVOutputClient client = TestUtility.GetMockClient(out MockHttpMessageHandler testProvider);
+
+ testProvider.ExpectUriFromBase(REGISTERNOTIFICATION_URL)
+ .RespondPlainText("");
+
+ var exception = Assert.ThrowsAsync(async () =>
+ {
+ _ = await client.Notification.RegisterNotificationAsync("my.application.id", new string('*', 151));
+ });
+ }
+ }
+}
diff --git a/tests/PVOutput.Net.Tests/Modules/Notification/NotificationServiceTestsData.cs b/tests/PVOutput.Net.Tests/Modules/Notification/NotificationServiceTestsData.cs
new file mode 100644
index 0000000..f959aa3
--- /dev/null
+++ b/tests/PVOutput.Net.Tests/Modules/Notification/NotificationServiceTestsData.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace PVOutput.Net.Tests.Modules.Supply
+{
+ public partial class NotificationServiceTests
+ {
+ public const string REGISTERNOTIFICATION_URL = "registernotification.jsp";
+ public const string DEREGISTERNOTIFICATION_URL = "deregisternotification.jsp";
+ }
+}
diff --git a/tests/PVOutput.Net.Tests/PVOutput.Net.Tests.csproj b/tests/PVOutput.Net.Tests/PVOutput.Net.Tests.csproj
index 67a0d55..ec2e787 100644
--- a/tests/PVOutput.Net.Tests/PVOutput.Net.Tests.csproj
+++ b/tests/PVOutput.Net.Tests/PVOutput.Net.Tests.csproj
@@ -6,19 +6,19 @@
..\..\artifacts\
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
-
+
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+