From 60831fc51039799c2f4a47ba22f9878d0a83ef8f Mon Sep 17 00:00:00 2001 From: naveenmullapudi260006549 Date: Thu, 3 Sep 2026 00:28:10 +0530 Subject: [PATCH] Add current-source to rating models --- .../client/model/common/CurrentSource.java | 53 +++++++++++++++++ .../ForecastPeriodSnapshot.java | 8 +++ .../operatingsnapshots/RealTimeLimit.java | 8 +++ .../SeasonalPeriodSnapshot.java | 8 +++ .../ratingproposals/ForecastRatingPeriod.java | 8 +++ .../model/ratingproposals/RealTimeRating.java | 8 +++ .../energy/trolie/client/TrolieClientIT.java | 26 ++++----- .../model/common/CurrentSourceTest.java | 58 +++++++++++++++++++ 8 files changed, 164 insertions(+), 13 deletions(-) create mode 100644 java-client/src/main/java/energy/trolie/client/model/common/CurrentSource.java create mode 100644 java-client/src/test/java/energy/trolie/client/model/common/CurrentSourceTest.java diff --git a/java-client/src/main/java/energy/trolie/client/model/common/CurrentSource.java b/java-client/src/main/java/energy/trolie/client/model/common/CurrentSource.java new file mode 100644 index 0000000..301f1ee --- /dev/null +++ b/java-client/src/main/java/energy/trolie/client/model/common/CurrentSource.java @@ -0,0 +1,53 @@ +package energy.trolie.client.model.common; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Enumeration of the possible origins of a rating value, as reported by a + * ratings provider on a rating proposal. Preserves the provenance or quality + * of a rating value at the point of submission, distinguishing ratings that + * arose from sensor/calculation failures from those derived normally. + */ +public enum CurrentSource { + + /** + * The rating value was derived directly from telemetered sensor data. + */ + TELEMETERED, + + /** + * The rating value was derived from a calculation, such as a weather-based + * or dynamic rating calculation. + */ + CALCULATED, + + /** + * The rating value was estimated, typically as a fallback when telemetry + * or calculation inputs were unavailable or failed. + */ + ESTIMATED, + + /** + * The rating value was manually entered or overridden by an operator. + */ + MANUAL; + + /** + * @return the lower-case value used to represent this current-source in JSON. + */ + @JsonValue + public String toJson() { + return name().toLowerCase(); + } + + /** + * Resolves a {@link CurrentSource} from its JSON representation. + * @param value the JSON string value + * @return the matching {@link CurrentSource} + */ + @JsonCreator + public static CurrentSource fromJson(String value) { + return value == null ? null : CurrentSource.valueOf(value.toUpperCase()); + } +} diff --git a/java-client/src/main/java/energy/trolie/client/model/operatingsnapshots/ForecastPeriodSnapshot.java b/java-client/src/main/java/energy/trolie/client/model/operatingsnapshots/ForecastPeriodSnapshot.java index 4da5e01..84f3183 100644 --- a/java-client/src/main/java/energy/trolie/client/model/operatingsnapshots/ForecastPeriodSnapshot.java +++ b/java-client/src/main/java/energy/trolie/client/model/operatingsnapshots/ForecastPeriodSnapshot.java @@ -8,6 +8,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString; +import energy.trolie.client.model.common.CurrentSource; import energy.trolie.client.model.common.EmergencyRatingValue; import energy.trolie.client.model.common.RatingValue; @@ -40,4 +41,11 @@ public class ForecastPeriodSnapshot { @JsonProperty("emergency-operating-limits") private List emergencyOperatingLimits; + + /** + * Optional origin/quality of the rating value, e.g. telemetered, calculated, + * estimated, or manual. + */ + @JsonProperty("current-source") + private CurrentSource currentSource; } diff --git a/java-client/src/main/java/energy/trolie/client/model/operatingsnapshots/RealTimeLimit.java b/java-client/src/main/java/energy/trolie/client/model/operatingsnapshots/RealTimeLimit.java index 03f5335..f89f794 100644 --- a/java-client/src/main/java/energy/trolie/client/model/operatingsnapshots/RealTimeLimit.java +++ b/java-client/src/main/java/energy/trolie/client/model/operatingsnapshots/RealTimeLimit.java @@ -7,6 +7,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString; +import energy.trolie.client.model.common.CurrentSource; import energy.trolie.client.model.common.EmergencyRatingValue; import energy.trolie.client.model.common.RatingValue; @@ -32,4 +33,11 @@ public class RealTimeLimit { @JsonProperty("emergency-operating-limits") private List emergencyOperatingLimits; + /** + * Optional origin/quality of the rating value, e.g. telemetered, calculated, + * estimated, or manual. + */ + @JsonProperty("current-source") + private CurrentSource currentSource; + } diff --git a/java-client/src/main/java/energy/trolie/client/model/operatingsnapshots/SeasonalPeriodSnapshot.java b/java-client/src/main/java/energy/trolie/client/model/operatingsnapshots/SeasonalPeriodSnapshot.java index 4eb7c23..f6dc1d3 100644 --- a/java-client/src/main/java/energy/trolie/client/model/operatingsnapshots/SeasonalPeriodSnapshot.java +++ b/java-client/src/main/java/energy/trolie/client/model/operatingsnapshots/SeasonalPeriodSnapshot.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; +import energy.trolie.client.model.common.CurrentSource; import energy.trolie.client.model.common.EmergencyRatingValue; import energy.trolie.client.model.common.RatingValue; import lombok.AllArgsConstructor; @@ -41,4 +42,11 @@ public class SeasonalPeriodSnapshot { @JsonProperty("emergency-operating-limits") private List emergencyOperatingLimits; + + /** + * Optional origin/quality of the rating value, e.g. telemetered, calculated, + * estimated, or manual. + */ + @JsonProperty("current-source") + private CurrentSource currentSource; } diff --git a/java-client/src/main/java/energy/trolie/client/model/ratingproposals/ForecastRatingPeriod.java b/java-client/src/main/java/energy/trolie/client/model/ratingproposals/ForecastRatingPeriod.java index 32de3cb..b27288f 100644 --- a/java-client/src/main/java/energy/trolie/client/model/ratingproposals/ForecastRatingPeriod.java +++ b/java-client/src/main/java/energy/trolie/client/model/ratingproposals/ForecastRatingPeriod.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; +import energy.trolie.client.model.common.CurrentSource; import energy.trolie.client.model.common.InputValue; import lombok.AllArgsConstructor; import lombok.Builder; @@ -40,4 +41,11 @@ public class ForecastRatingPeriod { @JsonProperty("inputs-used") private List inputsUsed; + + /** + * Optional origin/quality of the rating value, e.g. telemetered, calculated, + * estimated, or manual. + */ + @JsonProperty("current-source") + private CurrentSource currentSource; } diff --git a/java-client/src/main/java/energy/trolie/client/model/ratingproposals/RealTimeRating.java b/java-client/src/main/java/energy/trolie/client/model/ratingproposals/RealTimeRating.java index c321e9c..afecf1b 100644 --- a/java-client/src/main/java/energy/trolie/client/model/ratingproposals/RealTimeRating.java +++ b/java-client/src/main/java/energy/trolie/client/model/ratingproposals/RealTimeRating.java @@ -6,6 +6,7 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; +import energy.trolie.client.model.common.CurrentSource; import energy.trolie.client.model.common.EmergencyRatingValue; import energy.trolie.client.model.common.InputValue; import energy.trolie.client.model.common.RatingValue; @@ -33,4 +34,11 @@ public class RealTimeRating { @JsonProperty("inputs-used") private List inputsUsed; + + /** + * Optional origin/quality of the rating value, e.g. telemetered, calculated, + * estimated, or manual. + */ + @JsonProperty("current-source") + private CurrentSource currentSource; } diff --git a/java-client/src/test/java/energy/trolie/client/TrolieClientIT.java b/java-client/src/test/java/energy/trolie/client/TrolieClientIT.java index edf0a83..b0c3910 100644 --- a/java-client/src/test/java/energy/trolie/client/TrolieClientIT.java +++ b/java-client/src/test/java/energy/trolie/client/TrolieClientIT.java @@ -1938,12 +1938,12 @@ private void writeForecastSnapshot(JsonGenerator json, Instant startTime) throws json.writeFieldName("periods"); json.writeStartArray(); for (int j=0;j<24;j++) { - ForecastPeriodSnapshot period = new ForecastPeriodSnapshot( - startTime, - startTime, - RatingValue.fromMva(100f), - Collections.emptyList() - ); + ForecastPeriodSnapshot period = ForecastPeriodSnapshot.builder() + .periodStart(startTime) + .periodEnd(startTime) + .continuousOperatingLimit(RatingValue.fromMva(100f)) + .emergencyOperatingLimits(Collections.emptyList()) + .build(); json.writeObject(period); } json.writeEndArray(); @@ -1995,13 +1995,13 @@ private void writeSeasonalSnapshot(JsonGenerator json, Instant startTime, String json.writeFieldName("periods"); json.writeStartArray(); for (int j=0;j<24;j++) { - SeasonalPeriodSnapshot period = new SeasonalPeriodSnapshot( - startTime, - startTime, - season, - RatingValue.fromMva(100f), - Collections.emptyList() - ); + SeasonalPeriodSnapshot period = SeasonalPeriodSnapshot.builder() + .periodStart(startTime) + .periodEnd(startTime) + .seasonName(season) + .continuousOperatingLimit(RatingValue.fromMva(100f)) + .emergencyOperatingLimits(Collections.emptyList()) + .build(); json.writeObject(period); } json.writeEndArray(); diff --git a/java-client/src/test/java/energy/trolie/client/model/common/CurrentSourceTest.java b/java-client/src/test/java/energy/trolie/client/model/common/CurrentSourceTest.java new file mode 100644 index 0000000..a27f147 --- /dev/null +++ b/java-client/src/test/java/energy/trolie/client/model/common/CurrentSourceTest.java @@ -0,0 +1,58 @@ +package energy.trolie.client.model.common; + +import com.fasterxml.jackson.databind.ObjectMapper; +import energy.trolie.client.model.operatingsnapshots.RealTimeLimit; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +class CurrentSourceTest { + + private final ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void serializes_to_lowercase_json_value() throws IOException { + assertEquals("\"telemetered\"", objectMapper.writeValueAsString(CurrentSource.TELEMETERED)); + assertEquals("\"calculated\"", objectMapper.writeValueAsString(CurrentSource.CALCULATED)); + assertEquals("\"estimated\"", objectMapper.writeValueAsString(CurrentSource.ESTIMATED)); + assertEquals("\"manual\"", objectMapper.writeValueAsString(CurrentSource.MANUAL)); + } + + @Test + void deserializes_from_lowercase_json_value() throws IOException { + assertEquals(CurrentSource.TELEMETERED, objectMapper.readValue("\"telemetered\"", CurrentSource.class)); + assertEquals(CurrentSource.CALCULATED, objectMapper.readValue("\"calculated\"", CurrentSource.class)); + assertEquals(CurrentSource.ESTIMATED, objectMapper.readValue("\"estimated\"", CurrentSource.class)); + assertEquals(CurrentSource.MANUAL, objectMapper.readValue("\"manual\"", CurrentSource.class)); + } + + @Test + void field_is_optional_on_real_time_limit() throws IOException { + RealTimeLimit withoutCurrentSource = RealTimeLimit.builder() + .resourceId("resource1") + .continuousOperatingLimit(RatingValue.fromMva(100f)) + .build(); + + String json = objectMapper.writeValueAsString(withoutCurrentSource); + RealTimeLimit roundTripped = objectMapper.readValue(json, RealTimeLimit.class); + + assertNull(roundTripped.getCurrentSource()); + } + + @Test + void field_round_trips_on_real_time_limit() throws IOException { + RealTimeLimit withCurrentSource = RealTimeLimit.builder() + .resourceId("resource1") + .continuousOperatingLimit(RatingValue.fromMva(100f)) + .currentSource(CurrentSource.MANUAL) + .build(); + + String json = objectMapper.writeValueAsString(withCurrentSource); + RealTimeLimit roundTripped = objectMapper.readValue(json, RealTimeLimit.class); + + assertEquals(CurrentSource.MANUAL, roundTripped.getCurrentSource()); + } +}