private static void ValidateSetStatus(IntervalReading intervalReading, List <Exception> exceptions) { if (intervalReading.StatusFNN == null && !intervalReading.StatusPTB.HasValue) { exceptions.Add(new InvalidOperationException("Das Element \"IntervalReading\" muss mindestens \"StatusFNN\" oder \"StatusPTB\" mit einem gültigen Wert enthalten.")); return; } if (intervalReading.StatusFNN != null && !intervalReading.StatusPTB.HasValue) { if (string.IsNullOrWhiteSpace(intervalReading.StatusFNN.Status)) { exceptions.Add(new InvalidOperationException("Das Element \"IntervalReading\" muss mindestens \"StatusFNN\" oder \"StatusPTB\" mit einem gültigen Wert enthalten.")); } else { if (!intervalReading.StatusFNN.ValidateFNNStatus()) { exceptions.Add(new InvalidOperationException("Das Element \"StatusFNN\" hat keinen gültigen Wert.")); } } } else if (intervalReading.StatusFNN == null && intervalReading.StatusPTB.HasValue) { ValidateIntervalReadingStatusPTB(intervalReading.StatusPTB, exceptions); } }
private static void Taf1RegisterMeterReading(this MeterReading meterReading, MeterReading oml, BillingPeriod billingPeriod, MeterReadingConfig meterReadingConfig) { var intervalBlock = InitIntervalBlockWithInterval(billingPeriod.Begin, (DateTime)billingPeriod.End); var period = meterReadingConfig.Taf1PeriodInMonth; var requiredValues = GetRequiredIntervalReadingsFromOML(oml, billingPeriod.Begin, (DateTime)billingPeriod.End); var timestamp = billingPeriod.Begin.AddMonths(period); var initValue = requiredValues.FirstOrDefault(val => val.TimePeriod.Start == billingPeriod.Begin).Value; var value = GetNextValue(initValue, requiredValues, timestamp, (DateTime)billingPeriod.End); while (timestamp <= billingPeriod.End) { var ir = new IntervalReading() { TimePeriod = new Interval() { Duration = 0, Start = timestamp }, Value = value }; SetStatusWord(ir, meterReadingConfig); ir.IntervalBlock = intervalBlock; intervalBlock.IntervalReadings.Add(ir); timestamp = timestamp.AddMonths(period); value = GetNextValue(initValue, requiredValues, timestamp, (DateTime)billingPeriod.End); } intervalBlock.MeterReading = meterReading; meterReading.IntervalBlocks.Add(intervalBlock); }
/// <summary> /// Gets the CSS class for the status icon from the specified interval reading. /// </summary> /// <param name="reading">The interval reading.</param> /// <returns>The CSS class of the status icon.</returns> public static string ToStatusIcon(this IntervalReading reading) { if (reading == null || (reading.StatusPTB == null && reading.StatusFNN == null)) { return(string.Empty); } var status = reading.StatusPTB ?? reading.StatusFNN.MapToStatusPtb(); return(status.ToStatusIcon()); }
public HistoricConsumption(IntervalReading startReading, IntervalReading endReading, DateTime begin, DateTime end, TimeUnit unitOfTime) { if (startReading?.Value != null && endReading?.Value != null) { this.Value = endReading.Value - startReading.Value; } this.UnitOfTime = unitOfTime; this.Begin = begin; this.End = end; }
private static void SetStatusWord(IntervalReading ir, MeterReadingConfig config) { if (config.UsedStatus == "FNN") { ir.StatusFNN = new StatusFNN(GetStatusFNN()); } else if (config.UsedStatus == "PTB") { ir.StatusPTB = (StatusPTB)GetRandomNumber(0, 4); } }
/// <summary> /// If a intervalReading to the tariff change timestamp is needed, this method will be called. /// </summary> /// <param name="meterReading">The raw data.</param> /// <param name="end">The date for the meterReading</param> /// <param name="index">the index of the parent loop</param> /// <returns>An intervalReading or null</returns> public (IntervalReading reading, DateTime end) SetIntervalReading(MeterReading meterReading, DateTime end, int index, int dayTimeProfilesCount) { var date = LocalSetLastReading(end, index, dayTimeProfilesCount); var reading = meterReading.GetIntervalReadingFromDate(date); // If there is a gap at 0:00 o'clock the next day if (date > end && (reading == null || !IsStatusValid(reading))) { date = end; reading = meterReading.GetIntervalReadingFromDate(date); } return(reading, date); }
/// <summary> /// This value is needed if there is a gap between 2 days. /// </summary> /// <param name="latestReading">The current latest reading</param> /// <param name="reading">The current reading with a possible new value for latestReading</param> /// <returns>The latest reading value</returns> public long GetLatestReading(long latestReading, IntervalReading reading) { var result = latestReading; if (reading != null && IsStatusValid(reading)) { if (reading.Value.HasValue) { result = reading.Value > latestReading ? (long)reading.Value : latestReading; } } return(result); }
/// <summary> /// Check if the IntervalReading instance has an valid status /// </summary> /// <param name="reading">The IntervalReading object to check.</param> /// <returns>True if the status is valid.</returns> private bool IsStatusValid(IntervalReading reading) { if (reading != null) { var fnnStatusToPtbStatus = reading.StatusFNN?.MapToStatusPtb(); var ptbStatus = reading.StatusPTB; return(fnnStatusToPtbStatus != StatusPTB.CriticalTemporaryError && fnnStatusToPtbStatus != StatusPTB.FatalError && ptbStatus != StatusPTB.CriticalTemporaryError && ptbStatus != StatusPTB.FatalError); } return(false); }
/// <summary> /// Converts the status of the interval reading to the PTB status text. /// </summary> /// <param name="reading">The interval reading.</param> /// <param name="count">The count used for the distinction between plural and singular.</param> /// <returns>The status text.</returns> public static string ToStatusString(this IntervalReading reading, int count = 1) { if (reading == null || (reading.StatusPTB == null && reading.StatusFNN == null)) { return(string.Empty); } if (reading.StatusFNN != null) { return(GetFnnStatusString(reading.StatusFNN, count)); } var status = reading.StatusPTB ?? reading.StatusFNN.MapToStatusPtb(); return(status.GetStatusString(count)); }
private static void Taf2RegisterMeterReading(this MeterReading meterReading, MeterReading oml, BillingPeriod billingPeriod, MeterReadingConfig meterReadingConfig, List <Taf2Data> taf2Data) { var intervalBlock = InitIntervalBlockWithInterval(billingPeriod.Begin, (DateTime)billingPeriod.End); var ObisCode = new ObisId(oml.ReadingType.ObisCode); var taf2 = taf2Data.FirstOrDefault(t => t.ObisID.ToHexString() == ObisCode.ToHexString()); var requiredValues = GetRequiredIntervalReadingsFromOML(oml, billingPeriod.Begin, (DateTime)billingPeriod.End); int value = 0; if (new ObisId(meterReading.ReadingType.ObisCode).E == 0) { foreach ((DateTime timestamp, int tariff, int value)item in taf2.Data) { if (item.timestamp >= billingPeriod.Begin && item.timestamp <= (DateTime)billingPeriod.End) { value = value + item.value; } } } else { foreach ((DateTime timestamp, int tariff, int value)item in taf2.Data) { if (item.timestamp >= billingPeriod.Begin && item.timestamp <= (DateTime)billingPeriod.End && item.tariff == meterReadingConfig.Taf2TariffStage) { value = value + item.value; } } } var ir = new IntervalReading() { TimePeriod = new Interval() { Duration = (uint)(billingPeriod.End - billingPeriod.Begin)?.TotalSeconds, Start = billingPeriod.Begin }, Value = value }; SetStatusWord(ir, meterReadingConfig); ir.IntervalBlock = intervalBlock; intervalBlock.IntervalReadings.Add(ir); intervalBlock.MeterReading = meterReading; meterReading.IntervalBlocks.Add(intervalBlock); }
// Validation of an IntervalReading instance private static void ValidateIntervalReading(IntervalReading intervalReading, List <Exception> exceptions) { if (intervalReading.TimePeriod == null) { exceptions.Add(new InvalidOperationException("Das Element \"IntervalReading\" muss das Element \"TimePeriod\" enthalten.")); } else { ValidateInterval(intervalReading.TimePeriod, "timePeriod", exceptions); } if (!intervalReading.Value.HasValue) { exceptions.Add(new InvalidOperationException("Das Element \"value\" enthält keinen gültigen Wert.")); } ValidateSetStatus(intervalReading, exceptions); }
/// <summary> /// Gets the background color of the status from specified interval reading. /// </summary> /// <param name="reading">The interval reading.</param> /// <returns>The CSS class.</returns> public static string ToStatusBackground(this IntervalReading reading) { if (reading == null) { return(string.Empty); } if (reading.Value == null) { return("bg-warning"); } if (reading.StatusPTB == null && reading.StatusFNN == null) { return(string.Empty); } var status = reading.StatusPTB ?? reading.StatusFNN.MapToStatusPtb(); switch (status) { case StatusPTB.NoError: return(string.Empty); case StatusPTB.Warning: return("bg-warning"); case StatusPTB.TemporaryError: return("bg-warning"); case StatusPTB.CriticalTemporaryError: return("bg-warning"); case StatusPTB.FatalError: return("bg-danger"); default: throw new ArgumentOutOfRangeException(); } }
private static void OriginalValueList(this MeterReading meterReading, HanAdapterExampleConfig hanConfiguration, MeterReadingConfig meterReadingConfig, List <Taf2Data> taf2Data) { var intervalBlock = InitIntervalBlockWithInterval((DateTime)hanConfiguration.Start, (DateTime)hanConfiguration.End); var taf2 = new Taf2Data(new ObisId(meterReading.ReadingType.ObisCode)); var value = meterReadingConfig.OMLInitValue; var preValue = value; var timestamp = intervalBlock.Interval.Start.ToUniversalTime(); var end = intervalBlock.Interval.GetEnd().GetDateWithoutSeconds().ToUniversalTime(); while (timestamp <= end) { var ir = new IntervalReading() { TimePeriod = new Interval() { Duration = 0, Start = timestamp.ToLocalTime() }, Value = value }; if (preValue != value) { taf2.Data.Add((timestamp.ToLocalTime(), GetRandomNumber(0, meterReadingConfig.Taf2TariffStages), value - preValue)); } preValue = value; value = value + GetRandomNumber(1, hanConfiguration.XmlConfig.MaxConsumptionValue); timestamp = timestamp.AddSeconds(meterReadingConfig.PeriodSeconds.Value).GetDateWithoutSeconds(); SetStatusWord(ir, meterReadingConfig); ir.IntervalBlock = intervalBlock; intervalBlock.IntervalReadings.Add(ir); } taf2Data.Add(taf2); intervalBlock.MeterReading = meterReading; meterReading.IntervalBlocks.Add(intervalBlock); }
/// <summary> /// This method is used to create an empty endReading object /// </summary> /// <returns></returns> public static (IntervalReading reading, DateTime end) SetConcreteIntervalReading(IntervalReading reading, DateTime end) { return(reading, end); }
/// <summary> /// The main calculation method for the accounting period in Taf-1. /// </summary> /// <param name="supplier">Contains the calculation data.</param> /// <param name="meterReading">The MeterReading instance with the raw data.</param> /// <param name="startReading">The intervalReading at the beginning of the section.</param> /// <param name="endReading">The intervalReading at the end of the section.</param> /// <param name="tariffId">The valid tariffId.</param> /// <returns>The calculated AccountingSection</returns> public AccountingMonth GetSection(UsagePointLieferant supplier, MeterReading meterReading, IntervalReading startReading, IntervalReading endReading, ushort tariffId) { var registers = supplier.GetRegister(); this.UpdateReadingTypeFromOriginalValueList(registers); var section = new AccountingMonth(registers) { Reading = new Reading() { Amount = startReading.Value, ObisCode = new ObisId(meterReading.ReadingType.ObisCode) } }; var start = startReading.TargetTime.Value; var end = endReading.TargetTime.Value; long amount = (long)(endReading.Value - startReading.Value); var range = new MeasuringRange(start, end, tariffId, amount); section.Add(range); section.Start = start; return(section); }
private static void CheckIntervalReading(IntervalReading ir, string targetTime, string captureTime, long value) { Assert.AreEqual(ir.Value, value); Assert.AreEqual(targetTime, ir.TargetTime?.ToString("yyyy-MM-ddTHH:mm:ssK")); Assert.AreEqual(captureTime, ir.CaptureTime.ToString("yyyy-MM-ddTHH:mm:ssK")); }
/// <summary> /// Searches the next valid startReading (In case the first value or values of the day are gaps) /// </summary> /// <param name="start">the current timestamp.</param> /// <param name="dayTimeProfiles">The dayTimeProfiles for the current day.</param> /// <param name="profile">The specialDayProfile of the current day.</param> /// <param name="meterReading">The meterReading object of the current original value list.</param> /// <param name="currentDay">The current AccountingDay object.</param> /// <param name="dtpIndex">The current dayTimeProfiles index.</param> /// <param name="latestReading">The current meterReading value.</param> /// <param name="lastTariffId">The last valid tariff id.</param> /// <returns>The next valid start value.</returns> public (IntervalReading startReading, int index, long latestReading, ushort tariffId) GetStartReading(DateTime start, List <DayTimeProfile> dayTimeProfiles, SpecialDayProfile profile, MeterReading meterReading, AccountingDay currentDay, int dtpIndex, long latestReading, ushort lastTariffId) { var dayStart = start; var startReading = new IntervalReading(); var index = dtpIndex; for (int i = 1; i < dayTimeProfiles.Count; i++) { start = ModelExtensions.GetDateTimeFromSpecialDayProfile(profile, dayTimeProfiles[i]); startReading = meterReading.GetIntervalReadingFromDate(start); // If the gap reaches the next tariff change if (dayTimeProfiles[i].TariffNumber != lastTariffId && lastTariffId != 63) { lastTariffId = 63; } // Checks if a startReading is found if (startReading != null && IsStatusValid(startReading)) { currentDay.Add(new MeasuringRange() { Start = dayStart, End = start, Amount = (startReading.Value.Value - latestReading), TariffId = lastTariffId }, new ObisId(meterReading.ReadingType.ObisCode)); index = i; latestReading = GetLatestReading(latestReading, startReading); lastTariffId = (ushort)dayTimeProfiles[i].TariffNumber; break; } else { index = i; } } // if no startReading for the whole day was found, set index to 96 if ((startReading == null || !IsStatusValid(startReading)) && index == dayTimeProfiles.Count - 1) { var nextDay0OClock = start.AddSeconds(900); startReading = meterReading.GetIntervalReadingFromDate(nextDay0OClock); // Check if a value for the next day at 0:00 o Clock exists if (startReading != null && IsStatusValid(startReading)) { currentDay.Add(new MeasuringRange() { Start = dayStart, End = nextDay0OClock, Amount = startReading.Value.Value - latestReading, TariffId = lastTariffId }, new ObisId(meterReading.ReadingType.ObisCode)); } index = dayTimeProfiles.Count; } return(startReading, index, latestReading, lastTariffId); }
/// <summary> /// Calculates the next valid range for the current day /// </summary> /// <param name="reading">The IntervalReading at the end of the new range.</param> /// <param name="endCurrentReading">The end date of the current range.</param> /// <param name="startReading">The IntervalReading at the start of the new range.</param> /// <param name="start">The start date of the current range.</param> /// <param name="end">The global end date of the current day.</param> /// <param name="dayTimeProfiles">The dayTimeProfiles for the current day.</param> /// <param name="meterReading">The meterReading object of the current original value list.</param> /// <param name="profile">The current SpecialDayProfile.</param> /// <param name="currentDay">The current AccountingDay object.</param> /// <param name="i">The current index value of the parent loop.</param> /// <param name="latestReading">The current meterReading value.</param> /// <param name="latestTariffId">The last valid tariff id.</param> /// <returns>The rangeData of the found range</returns> public (IntervalReading reading, MeasuringRange range, int index, long latestReading) GetNextRange(IntervalReading reading, DateTime endCurrentReading, IntervalReading startReading, DateTime start, DateTime end, List <DayTimeProfile> dayTimeProfiles, MeterReading meterReading, SpecialDayProfile profile, AccountingDay currentDay, int i, long latestReading, ushort latestTariffId) { var endReading = SetConcreteIntervalReading(reading, endCurrentReading); var range = new MeasuringRange(); // Normal situation: reading is valid. if (endReading.reading != null && IsStatusValid(endReading.reading)) { range = new MeasuringRange(start, endReading.end, (ushort)dayTimeProfiles[i - 1].TariffNumber, (endReading.reading.Value.Value - startReading.Value.Value)); } else // A gap was found { // Looking for the next valid IntervalReading var result = FindLastValidTime(start, end, profile, dayTimeProfiles, meterReading, i - 1); endReading = SetIntervalReading(meterReading, result.end, result.index, dayTimeProfiles.Count); if (result.end < end && endReading.reading != null) // An IntervalReading was found which is bigger than startReading but smaller than the detected gap. { range = new MeasuringRange(start, endReading.end, (ushort)dayTimeProfiles[result.index].TariffNumber, (endReading.reading.Value.Value - startReading.Value.Value)); } else { // Count in error register if (endReading.reading != null && IsStatusValid(endReading.reading)) { range = new MeasuringRange(start, endReading.end, (endReading.reading.Value.Value - startReading.Value.Value)); } else { // No closing valid IntervalReading for the current day was found (There was a gap at the last tariff change) latestTariffId = 63; endReading.reading = startReading; // No valid IntervalReading was found. Reset range to mark it as invalid. } } // 1 Measurement period at tariff change is missing if ((i - 1) == result.index) { latestReading = this.GetLatestReading(latestReading, endReading.reading); latestTariffId = range.TariffId; currentDay.Add(range, new ObisId(meterReading.ReadingType.ObisCode)); var j = result.index; var nextDate = ModelExtensions.GetDateTimeFromSpecialDayProfile(profile, dayTimeProfiles[j + 1]); var nextReading = SetIntervalReading(meterReading, nextDate, j + 1, dayTimeProfiles.Count); while (nextReading.reading == null || !IsStatusValid(nextReading.reading)) { j++; if (j < dayTimeProfiles.Count - 1) { nextDate = ModelExtensions.GetDateTimeFromSpecialDayProfile(profile, dayTimeProfiles[j + 1]); nextReading = SetIntervalReading(meterReading, nextDate, j + 1, dayTimeProfiles.Count); } else { nextDate = ModelExtensions.GetDateTimeFromSpecialDayProfile(profile, dayTimeProfiles[j]); nextReading = SetIntervalReading(meterReading, nextDate, j, dayTimeProfiles.Count); if (nextReading.reading == null || !IsStatusValid(endReading.reading)) { nextReading = endReading; break; } } } // Count in error register range = new MeasuringRange(endReading.end, nextReading.end, (nextReading.reading.Value.Value - endReading.reading.Value.Value)); endReading = nextReading; result.index = j + 1; } // Protect for the special case i == dayTimeProfiles.Count -1 because it could lead to an endless loop. if (i != dayTimeProfiles.Count - 1) { i = result.index; } } // Check if the range object is empty if (this.IsRangeEmpty(range)) { range.TariffId = latestTariffId; } return(endReading.reading, range, i, latestReading); }