Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace HeimdallPower.Api.Client.GridInsights.Lines;
namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;

public record ConductorTemperatureDto
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace HeimdallPower.Api.Client.GridInsights.Lines;
namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;

public record CurrentDto
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;

public record IcingDto
{
/// <summary>
/// The maximum icing data, i.e. max ice weight, max tension and max percentage of tensions, across all span phases on the line.
/// </summary>
public required MaxIcingDto Max { get; init; }

/// <summary>
/// List of spans on the line with their icing data.
/// </summary>
public required IReadOnlyCollection<SpanIcingDto> Spans { get; init; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;

public record MaxIcingDto
{
/// <summary>
/// The maximum mass of ice accumulated on the conductor.
/// </summary>
public required SpanPhaseMeasurementResult IceWeight { get; init; }

/// <summary>
/// The maximum mechanical tension force in the conductor, which increases as ice accumulates.
/// </summary>
public required SpanPhaseMeasurementResult Tension { get; init; }

/// <summary>
/// Maximum safety-critical metric showing how close the conductor is to its breaking point.
/// </summary>
public required SpanPhaseMeasurementResult TensionPercentageOfBreakStrength { get; init; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;

public record MeasurementResult()
{
/// <summary>
/// The numerical value of the measurement.
/// </summary>
public double Value { get; init; }

/// <summary>
/// The unit of the measurement.
/// </summary>
public required string Unit { get; init; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;

public record SpanIcingDto
{
/// <summary>
/// The id of the span.
/// </summary>
/// <example>00000000-0000-0000-0000-000000000000</example>
public Guid SpanId { get; init; }

/// <summary>
/// List of span phases (conductors) within this span.
/// </summary>
public required IReadOnlyCollection<SpanPhaseIcingDto> SpanPhases { get; init; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;

public record SpanPhaseIcingDto
{
/// <summary>
/// The id of the span phase the measurement belongs to.
/// </summary>
/// <example>00000000-0000-0000-0000-000000000000</example>
public Guid SpanPhaseId { get; init; }

/// <summary>
/// Time (UTC) when the icing measurements were calculated for the span phase. Timestamps may differ per conductor due to data availability.
/// </summary>
/// <example>2024-01-15T12:34:56Z</example>
public DateTimeOffset Timestamp { get; init; }

/// <summary>
/// The mass of ice accumulated on the conductor.
/// </summary>
public required MeasurementResult IceWeight { get; init; }

/// <summary>
/// The mechanical tension force in the conductor, which increases as ice accumulates.
/// </summary>
public required MeasurementResult Tension { get; init; }

/// <summary>
/// Safety-critical metric showing how close the conductor is to its breaking point.
/// </summary>
public required MeasurementResult TensionPercentageOfBreakStrength { get; init; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace HeimdallPower.Api.Client.GridInsights.Lines.Dtos;

public record SpanPhaseMeasurementResult
{
/// <summary>
/// Time (UTC) when the icing measurements were calculated for the span phase. Timestamps may differ per conductor due to data availability.
/// </summary>
/// <example>2024-01-15T12:34:56Z</example>
public DateTimeOffset Timestamp { get; init; }

/// <summary>
/// The id of the span phase the measurement belongs to.
/// </summary>
/// <example>00000000-0000-0000-0000-000000000000</example>
public Guid SpanPhaseId { get; init; }

/// <summary>
/// The numerical value of the measurement.
/// </summary>
public double Value { get; init; }

/// <summary>
/// The unit of the measurement value.
/// </summary>
public required string Unit { get; init; }
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using HeimdallPower.Api.Client.GridInsights.Lines.Dtos;

namespace HeimdallPower.Api.Client.GridInsights.Lines;

public record LatestConductorTemperatureResponse
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using HeimdallPower.Api.Client.GridInsights.Lines.Dtos;

namespace HeimdallPower.Api.Client.GridInsights.Lines;

public record LatestCurrentResponse
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using HeimdallPower.Api.Client.GridInsights.Lines.Dtos;

namespace HeimdallPower.Api.Client.GridInsights.Lines;

public record LatestIcingResponse
{
/// <summary>
/// The kind of data this response contains.
/// </summary>
/// <example>Icing</example>
public required string Metric { get; init; }

/// <summary>
/// The unit description for the response (multiple units across measurements).
/// </summary>
/// <example>Multiple (see measurements)</example>
public required string Unit { get; init; }

/// <summary>
/// The icing measurements including max and per-span/phase values.
/// </summary>
public required IcingDto Icing { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,19 @@ public async Task<LatestConductorTemperatureResponse> GetLatestConductorTemperat
return response.Data;
}

/// <summary>
/// Get the most recent icing measurements for the line, including maximum values and per-span/phase metrics.
/// </summary>
/// <param name="lineId">Id of the line for which to retrieve the latest icing measurements.</param>
/// <param name="unitSystem">The unit system for the measurements. "metric" uses kg/m, N, %, while "imperial" uses lb/ft, lbf, %.</param>
/// <param name="since">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.</param>
public async Task<LatestIcingResponse> GetLatestIcingAsync(Guid lineId, string unitSystem = "metric", DateTimeOffset? since = null)
{
var url = UrlBuilder.BuildLatestIcingUrl(lineId, unitSystem, since);
var response = await _heimdallApiClient.GetAsync<ApiResponse<LatestIcingResponse>>(url);
return response.Data;
}

/// <summary>
/// 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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}";

Expand Down
2 changes: 2 additions & 0 deletions dotnet/examples/Api.Client.Examples/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down