diff --git a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/ConductorTemperatureDto.cs b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/ConductorTemperatureDto.cs
similarity index 91%
rename from dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/ConductorTemperatureDto.cs
rename to dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/ConductorTemperatureDto.cs
index 17ddf5a..890544d 100644
--- a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/ConductorTemperatureDto.cs
+++ b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/ConductorTemperatureDto.cs
@@ -1,4 +1,4 @@
-namespace HeimdallPower.Api.Client.GridInsights.Lines;
+namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;
public record ConductorTemperatureDto
{
diff --git a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/CurrentDto.cs b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/CurrentDto.cs
similarity index 86%
rename from dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/CurrentDto.cs
rename to dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/CurrentDto.cs
index bc69cfd..63799d6 100644
--- a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/CurrentDto.cs
+++ b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/CurrentDto.cs
@@ -1,4 +1,4 @@
-namespace HeimdallPower.Api.Client.GridInsights.Lines;
+namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;
public record CurrentDto
{
diff --git a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/IcingDto.cs b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/IcingDto.cs
new file mode 100644
index 0000000..15d236a
--- /dev/null
+++ b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/IcingDto.cs
@@ -0,0 +1,14 @@
+namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;
+
+public record IcingDto
+{
+ ///
+ /// The maximum icing data, i.e. max ice weight, max tension and max percentage of tensions, across all span phases on the line.
+ ///
+ public required MaxIcingDto Max { get; init; }
+
+ ///
+ /// List of spans on the line with their icing data.
+ ///
+ public required IReadOnlyCollection Spans { get; init; }
+}
diff --git a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/MaxIcingDto.cs b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/MaxIcingDto.cs
new file mode 100644
index 0000000..eabd65f
--- /dev/null
+++ b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/MaxIcingDto.cs
@@ -0,0 +1,19 @@
+namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;
+
+public record MaxIcingDto
+{
+ ///
+ /// The maximum mass of ice accumulated on the conductor.
+ ///
+ public required SpanPhaseMeasurementResult IceWeight { get; init; }
+
+ ///
+ /// The maximum mechanical tension force in the conductor, which increases as ice accumulates.
+ ///
+ public required SpanPhaseMeasurementResult Tension { get; init; }
+
+ ///
+ /// Maximum safety-critical metric showing how close the conductor is to its breaking point.
+ ///
+ public required SpanPhaseMeasurementResult TensionPercentageOfBreakStrength { get; init; }
+}
diff --git a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/MeasurementResult.cs b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/MeasurementResult.cs
new file mode 100644
index 0000000..7ee0d79
--- /dev/null
+++ b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/MeasurementResult.cs
@@ -0,0 +1,14 @@
+namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;
+
+public record MeasurementResult()
+{
+ ///
+ /// The numerical value of the measurement.
+ ///
+ public double Value { get; init; }
+
+ ///
+ /// The unit of the measurement.
+ ///
+ public required string Unit { get; init; }
+}
diff --git a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/SpanIcingDto.cs b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/SpanIcingDto.cs
new file mode 100644
index 0000000..eabc278
--- /dev/null
+++ b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/SpanIcingDto.cs
@@ -0,0 +1,15 @@
+namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;
+
+public record SpanIcingDto
+{
+ ///
+ /// The id of the span.
+ ///
+ /// 00000000-0000-0000-0000-000000000000
+ public Guid SpanId { get; init; }
+
+ ///
+ /// List of span phases (conductors) within this span.
+ ///
+ public required IReadOnlyCollection SpanPhases { get; init; }
+}
diff --git a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/SpanPhaseIcingDto.cs b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/SpanPhaseIcingDto.cs
new file mode 100644
index 0000000..6d6aea8
--- /dev/null
+++ b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/SpanPhaseIcingDto.cs
@@ -0,0 +1,31 @@
+namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;
+
+public record SpanPhaseIcingDto
+{
+ ///
+ /// The id of the span phase the measurement belongs to.
+ ///
+ /// 00000000-0000-0000-0000-000000000000
+ public Guid SpanPhaseId { get; init; }
+
+ ///
+ /// Time (UTC) when the icing measurements were calculated for the span phase. Timestamps may differ per conductor due to data availability.
+ ///
+ /// 2024-01-15T12:34:56Z
+ public DateTimeOffset Timestamp { get; init; }
+
+ ///
+ /// The mass of ice accumulated on the conductor.
+ ///
+ public required MeasurementResult IceWeight { get; init; }
+
+ ///
+ /// The mechanical tension force in the conductor, which increases as ice accumulates.
+ ///
+ public required MeasurementResult Tension { get; init; }
+
+ ///
+ /// Safety-critical metric showing how close the conductor is to its breaking point.
+ ///
+ public required MeasurementResult TensionPercentageOfBreakStrength { get; init; }
+}
diff --git a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/SpanPhaseMeasurementResult.cs b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/SpanPhaseMeasurementResult.cs
new file mode 100644
index 0000000..3915373
--- /dev/null
+++ b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/Dtos/SpanPhaseMeasurementResult.cs
@@ -0,0 +1,26 @@
+namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;
+
+public record SpanPhaseMeasurementResult
+{
+ ///
+ /// Time (UTC) when the icing measurements were calculated for the span phase. Timestamps may differ per conductor due to data availability.
+ ///
+ /// 2024-01-15T12:34:56Z
+ public DateTimeOffset Timestamp { get; init; }
+
+ ///
+ /// The id of the span phase the measurement belongs to.
+ ///
+ /// 00000000-0000-0000-0000-000000000000
+ public Guid SpanPhaseId { get; init; }
+
+ ///
+ /// The numerical value of the measurement.
+ ///
+ public double Value { get; init; }
+
+ ///
+ /// The unit of the measurement value.
+ ///
+ public required string Unit { get; init; }
+}
diff --git a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/LatestConductorTemperatureResponse.cs b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/LatestConductorTemperatureResponse.cs
index 375fdb9..d88f5ab 100644
--- a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/LatestConductorTemperatureResponse.cs
+++ b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/LatestConductorTemperatureResponse.cs
@@ -1,3 +1,5 @@
+using HeimdallPower.Api.Client.GridInsights.Lines.Dtos;
+
namespace HeimdallPower.Api.Client.GridInsights.Lines;
public record LatestConductorTemperatureResponse
diff --git a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/LatestCurrentResponse.cs b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/LatestCurrentResponse.cs
index 8300660..457dbe9 100644
--- a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/LatestCurrentResponse.cs
+++ b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/LatestCurrentResponse.cs
@@ -1,3 +1,5 @@
+using HeimdallPower.Api.Client.GridInsights.Lines.Dtos;
+
namespace HeimdallPower.Api.Client.GridInsights.Lines;
public record LatestCurrentResponse
diff --git a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/LatestIcingResponse.cs b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/LatestIcingResponse.cs
new file mode 100644
index 0000000..bb5ebdc
--- /dev/null
+++ b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/GridInsights/Lines/LatestIcingResponse.cs
@@ -0,0 +1,23 @@
+using HeimdallPower.Api.Client.GridInsights.Lines.Dtos;
+
+namespace HeimdallPower.Api.Client.GridInsights.Lines;
+
+public record LatestIcingResponse
+{
+ ///
+ /// The kind of data this response contains.
+ ///
+ /// Icing
+ public required string Metric { get; init; }
+
+ ///
+ /// The unit description for the response (multiple units across measurements).
+ ///
+ /// Multiple (see measurements)
+ public required string Unit { get; init; }
+
+ ///
+ /// The icing measurements including max and per-span/phase values.
+ ///
+ public required IcingDto Icing { get; init; }
+}
diff --git a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/HeimdallApiClient.cs b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/HeimdallApiClient.cs
index 7437fc7..31b0a53 100644
--- a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/HeimdallApiClient.cs
+++ b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/HeimdallApiClient.cs
@@ -90,6 +90,19 @@ public async Task GetLatestConductorTemperat
return response.Data;
}
+ ///
+ /// Get the most recent icing measurements for the line, including maximum values and per-span/phase metrics.
+ ///
+ /// Id of the line for which to retrieve the latest icing measurements.
+ /// The unit system for the measurements. "metric" uses kg/m, N, %, while "imperial" uses lb/ft, lbf, %.
+ /// Optional cutoff time (UTC). Only measurements at or after this instant are considered. Older data for a span phase is excluded. If omitted, defaults to 30 min ago.
+ public async Task GetLatestIcingAsync(Guid lineId, string unitSystem = "metric", DateTimeOffset? since = null)
+ {
+ var url = UrlBuilder.BuildLatestIcingUrl(lineId, unitSystem, since);
+ var response = await _heimdallApiClient.GetAsync>(url);
+ return response.Data;
+ }
+
///
/// Get the most recent Heimdall Dynamic Line Rating (DLR) for the line.
/// Heimdall DLR is calculated according to our own proprietary method, based on the CIGRE TB-601 standard for thermal calculation for OHLs.
diff --git a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/UrlBuilder.cs b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/UrlBuilder.cs
index 7f3d717..6e25850 100644
--- a/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/UrlBuilder.cs
+++ b/dotnet/HeimdallPower.Api.Client/HeimdallPower.Api.Client/UrlBuilder.cs
@@ -25,6 +25,7 @@ internal static class UrlBuilder
private const string HeimdallAar = "heimdall_aars/latest";
private const string HeimdallDlrForecast = "heimdall_dlrs/forecasts";
private const string HeimdallAarForecast = "heimdall_aars/forecasts";
+ private const string IcingLatest = "icing/latest";
public static string BuildLatestConductorTemperatureUrl(Guid lineId, string unitSystem)
{
@@ -58,6 +59,17 @@ public static string BuildCircuitRatingForecastUrl(Guid facilityId)
public static string BuildCircuitRatingUrl(Guid facilityId)
=> GetFullUrl(module: CapacityMonitoring, apiVersion: V1, resource: Facilities, resourceId: facilityId.ToString(), endpoint: CircuitRatingLatest);
+ public static string BuildLatestIcingUrl(Guid lineId, string unitSystem = "metric", DateTimeOffset? since = null)
+ {
+ var queryParams = new NameValueCollection()
+ .AddQueryParam("unit_system", unitSystem);
+
+ if (since.HasValue)
+ queryParams.AddQueryParam("since", since.Value.ToUniversalTime().ToString("o"));
+
+ return GetFullUrl(module: GridInsight, apiVersion: V1, resource: Lines, resourceId: lineId.ToString(), endpoint: IcingLatest, queryParams: queryParams);
+ }
+
private static string GetResourceUrl(string module, string apiVersion, string resource)
=> $"{module}/{apiVersion}/{resource}";
diff --git a/dotnet/examples/Api.Client.Examples/Program.cs b/dotnet/examples/Api.Client.Examples/Program.cs
index 8a09c0e..3939f86 100644
--- a/dotnet/examples/Api.Client.Examples/Program.cs
+++ b/dotnet/examples/Api.Client.Examples/Program.cs
@@ -24,9 +24,11 @@
// Fetch Aggregated Measurements data
var latestCurrent = await api.GetLatestCurrentAsync(line.Id);
var latestConductorTemperature = await api.GetLatestConductorTemperatureAsync(line.Id);
+var latestIcing = await api.GetLatestIcingAsync(line.Id);
Console.WriteLine($"- Current: {latestCurrent.Current.Value} {latestCurrent.Unit} at {latestCurrent.Current.Timestamp}");
Console.WriteLine($"- Conductor Temperature: {latestConductorTemperature.ConductorTemperature.Max} {latestConductorTemperature.Unit} at {latestConductorTemperature.ConductorTemperature.Timestamp}");
+Console.WriteLine($"- Icing: Maximum Ice weight: {latestIcing.Icing.Max.IceWeight.Value} at span phase: {latestIcing.Icing.Max.IceWeight.SpanPhaseId}");
// Fetch DLR data
var latestDlr = await api.GetLatestHeimdallDlrAsync(line.Id);