Example #1
0
        // Comparision of the CertIds
        private static void CompareCertIds(UsagePointAdapterTRuDI usagePoint, List <Exception> exceptions)
        {
            var         smgwCertIds        = usagePoint.Smgw.CertIds;
            List <byte> certificateCertIds = new List <byte>();

            foreach (Certificate cert in usagePoint.Certificates)
            {
                certificateCertIds.Add((byte)cert.CertId);
            }

            if (smgwCertIds.Count == certificateCertIds.Count)
            {
                bool match = false;
                foreach (byte sId in smgwCertIds)
                {
                    foreach (byte cId in certificateCertIds)
                    {
                        if (sId == cId)
                        {
                            match = true;
                            break;
                        }
                    }

                    if (!match)
                    {
                        exceptions.Add(new InvalidOperationException($"Das Smart Meter Gateway-Zertifikat mit der ID {sId} konnte nicht gefunden werden."));
                    }
                }
            }
            else
            {
                exceptions.Add(new InvalidOperationException("Die Anzahl der \"CertIds\" im Element \"SMGW\" entspricht nicht der Nummer der Zertifikate."));
            }
        }
Example #2
0
        // Check if the delivered supplier xml has an completely enrolled calendar
        private static void ValidateSupplierModelCompletelyEnrolledCalendar(UsagePointAdapterTRuDI model, UsagePointLieferant supplier, List <Exception> exceptions)
        {
            var period   = supplier.AnalysisProfile.BillingPeriod;
            var profiles = supplier.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles;

            var sdpCheckList = new Dictionary <DateTime, int>();
            var timestamp    = period.Start;
            var hasCounted   = false;

            while (timestamp <= period.GetEnd().AddDays(-1))
            {
                sdpCheckList.Add(timestamp, 0);

                timestamp = timestamp.AddDays(1);
            }

            foreach (var profile in profiles)
            {
                if (sdpCheckList.ContainsKey(profile.SpecialDayDate.GetDate()))
                {
                    sdpCheckList[profile.SpecialDayDate.GetDate()] += 1;
                    hasCounted = true;
                }
            }

            foreach (var item in sdpCheckList)
            {
                if (item.Value == 0 && hasCounted)
                {
                    exceptions.Add(new InvalidOperationException($"Tagesprofil für Tag {item.Key:dd.MM.yyy} nicht vorhanden."));
                }
            }
        }
Example #3
0
        // Validation of additional requirements
        public static void ValidateContext(UsagePointAdapterTRuDI usagePoint, AdapterContext ctx)
        {
            var exceptions = new List <Exception>();

            if (ctx != null)
            {
                ValidateMeterReadingCount(usagePoint, ctx, exceptions);
                ValidateMaximumTimeSpan(ctx, exceptions);

                if (ctx.Contract.TafId == TafId.Taf2)
                {
                    ValidateTaf2RegisterDurations(usagePoint, exceptions);
                }

                if (ctx.Contract.TafId == TafId.Taf7)
                {
                    ValidateTaf7MeterReadingsAreOriginalValueLists(usagePoint, exceptions);
                    ValidateTaf7PeriodsInInterval(usagePoint, exceptions);
                }
            }

            CompareCertIds(usagePoint, exceptions);
            ValidateCertificateRawData(usagePoint, exceptions);
            ValidateIntervalBlockConsistence(usagePoint, exceptions);

            if (exceptions.Any())
            {
                throw new AggregateException("Context error:>", exceptions);
            }
        }
Example #4
0
        // Validate of all the neccessary ids of the model xml match with the ids in the supplier xml
        private static void ValidateTaf7ModelSupplierCompatibility(UsagePointAdapterTRuDI model, UsagePointLieferant supplier, List <Exception> exceptions)
        {
            if (model.UsagePointId != supplier.UsagePointId)
            {
                exceptions.Add(new InvalidOperationException($"TAF-7: Die ID der Messlokation \"{model.UsagePointId}\" stimmt nicht mit der ID der Messlokation \"{supplier.UsagePointId}\" aus der Tarifdatei des Lieferanten überein."));
            }

            if (model.InvoicingParty.InvoicingPartyId != supplier.InvoicingParty.InvoicingPartyId)
            {
                exceptions.Add(new InvalidOperationException($"TAF-7: Die ID des Rechnungsstellers \"{model.InvoicingParty.InvoicingPartyId}\" stimmt nicht mit der ID des Rechnungssteller \"{supplier.InvoicingParty.InvoicingPartyId}\" aus der Tarifdatei des Lieferanten überein."));
            }

            if (model.ServiceCategory.Kind != supplier.ServiceCategory.Kind)
            {
                exceptions.Add(new InvalidOperationException($"TAF-7: Die Service-Kategory \"{model.ServiceCategory.Kind}\" stimmt nicht mit der Service-Kategory \"{supplier.ServiceCategory.Kind}\" aus der Tarifdatei des Lieferanten überein."));
            }

            if (string.Compare(model.Smgw.SmgwId, supplier.Smgw.SmgwId, StringComparison.OrdinalIgnoreCase) != 0)
            {
                exceptions.Add(new InvalidOperationException($"TAF-7: Die ID des Smart Meter Gateway \"{model.Smgw.SmgwId}\" stimmt nicht mit der ID \"{supplier.Smgw.SmgwId}\" aus der Tarifdatei des Lieferanten überein."));
            }

            if (model.TariffName != supplier.TariffName)
            {
                exceptions.Add(new InvalidOperationException($"TAF-7: Der Tarifname \"{model.TariffName}\" stimmt nicht mit dem Tariffnamen \"{supplier.TariffName}\" aus der Tarifdatei des Lieferanten überein."));
            }
        }
Example #5
0
 // Taf-7: Validate if all meter readings are original value lists
 private static void ValidateTaf7MeterReadingsAreOriginalValueLists(UsagePointAdapterTRuDI model, List <Exception> exceptions)
 {
     foreach (MeterReading reading in model.MeterReadings)
     {
         if (!reading.IsOriginalValueList())
         {
             exceptions.Add(new InvalidOperationException("TAF-7: The MeterReading is not an Original Value List."));
         }
     }
 }
Example #6
0
 // Check of the meterReadingIds are unique
 private static void ValidateMeterReadingIds(UsagePointAdapterTRuDI usagePoint, List <Exception> exceptions)
 {
     for (int i = 0; i < usagePoint.MeterReadings.Count; i++)
     {
         var reading = usagePoint.MeterReadings[i];
         for (int j = i + 1; j < usagePoint.MeterReadings.Count; j++)
         {
             if (reading.MeterReadingId == usagePoint.MeterReadings[j].MeterReadingId)
             {
                 exceptions.Add(new InvalidOperationException("Das Element \"MeterReadingId\" enthält keine eindeutigen Werte."));
             }
         }
     }
 }
Example #7
0
 // Check if the raw data of the certificates are valid certificates
 private static void ValidateCertificateRawData(UsagePointAdapterTRuDI usagePoint, List <Exception> exceptions)
 {
     foreach (Certificate certificate in usagePoint.Certificates)
     {
         try
         {
             var cert = certificate.GetCert();
         }
         catch (Exception e)
         {
             exceptions.Add(new InvalidOperationException($"Zertifikat konnte nicht gelesen werden: ID={certificate.CertId}, Typ={certificate.CertType}", e));
         }
     }
 }
Example #8
0
        // Check if the count of MeterReadings are Valid due to the TAF
        private static void ValidateMeterReadingCount(UsagePointAdapterTRuDI usagePoint, AdapterContext ctx, List <Exception> exceptions)
        {
            var meterReadingCount = usagePoint.MeterReadings.Count;

            if (ctx.BillingPeriod != null && ctx.BillingPeriod.End.HasValue)
            {
                if (ctx.Contract.TafId == TafId.Taf1 && meterReadingCount < 2)
                {
                    exceptions.Add(new InvalidOperationException("TAF-1 benötigt mindestens 2 Elemente von Typ \"MeterReading\"."));
                }

                if ((ctx.Contract.TafId == TafId.Taf2) && meterReadingCount < 5)
                {
                    exceptions.Add(new InvalidOperationException("TAF-2 benötigt mindestens 5 Elemente vom Typ \"MeterReading\"."));
                }
            }
        }
Example #9
0
        // Validation of additional requirements with additional supplier xml (only Taf-7)
        public static void ValidateContext(UsagePointAdapterTRuDI usagePoint, UsagePointLieferant supplierModel, AdapterContext ctx)
        {
            ValidateContext(usagePoint, ctx);

            var exceptions = new List <Exception>();

            ValidateTaf7ModelSupplierCompatibility(usagePoint, supplierModel, exceptions);
            ValidateSupplierModelTariffStageCount(supplierModel, exceptions);
            ValidateSpecialDayProfilesWithinBillingPeriod(supplierModel, exceptions);
            ValidateSupplierModelCompletelyEnrolledCalendar(usagePoint, supplierModel, exceptions);
            ValidateTarifStageOccurence(supplierModel, exceptions);
            ValidateSupplierModelDayProfileOccurence(supplierModel, exceptions);

            if (exceptions.Any())
            {
                throw new AggregateException("Taf-7 Context error:>", exceptions);
            }
        }
Example #10
0
        // The public method for the validation of the  han adapter model
        public static UsagePointAdapterTRuDI ValidateHanAdapterModel(UsagePointAdapterTRuDI usagePoint)
        {
            var exceptions = new List <Exception>();

            CommonModelValidation(usagePoint, exceptions);

            if (usagePoint.Customer == null)
            {
                exceptions.Add(new InvalidOperationException("Das Element \"UsagePoint\" muss das Element \"Customer\" enthalten."));
            }

            if (usagePoint.Certificates.Count < 1)
            {
                exceptions.Add(new InvalidOperationException("Das Element \"UsagePoint\" muss das Element \"Certificate\" enthalten."));
            }
            else
            {
                foreach (var cert in usagePoint.Certificates)
                {
                    ValidateCertificate(cert, exceptions);
                }
            }

            foreach (var meterReading in usagePoint.MeterReadings)
            {
                ValidateMeterReading(meterReading, exceptions);
            }

            if (usagePoint.LogEntries.Count >= 1)
            {
                foreach (var logEntry in usagePoint.LogEntries)
                {
                    ValidateLogEntry(logEntry, exceptions);
                }
            }

            if (exceptions.Any())
            {
                throw new AggregateException("Han Adapter Model error:>", exceptions);
            }

            return(usagePoint);
        }
Example #11
0
        // Taf-2: Validate if the durations in the different MeterReadings match
        private static void ValidateTaf2RegisterDurations(UsagePointAdapterTRuDI usagePoint, List <Exception> exceptions)
        {
            var interval = usagePoint.MeterReadings.FirstOrDefault(mr => !mr.IsOriginalValueList())?.GetMeterReadingInterval();

            if (interval == null)
            {
                return;
            }

            foreach (MeterReading reading in usagePoint.MeterReadings)
            {
                if (!reading.IsOriginalValueList())
                {
                    var intervalTest = reading.GetMeterReadingInterval();

                    if (interval.Duration != intervalTest.Duration)
                    {
                        exceptions.Add(new InvalidOperationException("TAF-2: Die Dauer der einzelnen Ablesungen stimmen nicht überein."));
                    }
                }
            }
        }
Example #12
0
        // Check if there is a gap between multiple IntervalBlocks or if the overlap
        private static void ValidateIntervalBlockConsistence(UsagePointAdapterTRuDI usagePoint, List <Exception> exceptions)
        {
            foreach (MeterReading reading in usagePoint.MeterReadings)
            {
                var intervalBlocks = reading.IntervalBlocks.OrderBy(ib => ib.Interval.Start).ToList();

                for (int i = 0; i < intervalBlocks.Count; i++)
                {
                    if (i < intervalBlocks.Count - 1)
                    {
                        if (intervalBlocks[i].Interval.GetEnd() < intervalBlocks[i + 1].Interval.Start)
                        {
                            exceptions.Add(new InvalidOperationException("Lücke zwischen zwei Intervallblöcken."));
                        }
                        else if (intervalBlocks[i].Interval.GetEnd() > intervalBlocks[i + 1].Interval.Start)
                        {
                            exceptions.Add(new InvalidOperationException("Es wurden zwei überlappende Intervallblöcke gefunden."));
                        }
                    }
                }
            }
        }
Example #13
0
        // Taf-7: Validate if all IntervalReadings are within the interval of the IntervalBlock
        private static void ValidateTaf7PeriodsInInterval(UsagePointAdapterTRuDI model, List <Exception> exceptions)
        {
            var originalValueLists = model.MeterReadings.Where(mr => mr.IsOriginalValueList());

            foreach (var reading in originalValueLists)
            {
                foreach (var ib in reading.IntervalBlocks)
                {
                    var intervalBlockEnd = ib.Interval.GetEnd();
                    foreach (var ir in ib.IntervalReadings)
                    {
                        if (ir.CaptureTime.ToUniversalTime() < ib.Interval.Start.ToUniversalTime())
                        {
                            exceptions.Add(new InvalidOperationException($"TAF-7: IntervalReading befindet sich nicht innerhalb des Zeitbereichs eines IntervalBlocks: Start des IntervalBlocks: {ib.Interval.Start}, Zeitpunkt des IntervalReading: {ir.TimePeriod.Start}, Kennziffer: {reading.ReadingType.ObisCode}"));
                        }
                        else if (ir.CaptureTime.ToUniversalTime() > intervalBlockEnd.ToUniversalTime())
                        {
                            exceptions.Add(new InvalidOperationException($"TAF-7: IntervalReading befindet sich nicht innerhalb des Zeitbereichs eines IntervalBlocks: Ende des IntervalBlocks: {intervalBlockEnd}, Zeitpunkt des IntervalReading: {ir.TimePeriod.GetEnd()}, Kennziffer: {reading.ReadingType.ObisCode}"));
                        }
                    }
                }
            }
        }
Example #14
0
        /// <inheritdoc />
        /// <summary>
        /// Calculates the derived register for Taf1.
        /// </summary>
        /// <param name="device">Date from the SMGW. There should be just original value lists.</param>
        /// <param name="supplier">The calculation data from the supplier.</param>
        /// <returns>An ITaf2Data instance. The object contains the calculated data.</returns>
        public TafAdapterData Calculate(UsagePointAdapterTRuDI device, UsagePointLieferant supplier)
        {
            this.originalValueLists =
                device.MeterReadings.Where(mr => mr.IsOriginalValueList()).Select(mr => new OriginalValueList(mr, device.ServiceCategory.Kind ?? Kind.Electricity)).ToList();

            if (!this.originalValueLists.Any())
            {
                throw new InvalidOperationException("Es ist keine originäre Messwertliste verfügbar.");
            }

            this.ValidateOriginalValueLists(originalValueLists, supplier, device.MeterReadings.Count);

            var registers = supplier.GetRegister();

            this.UpdateReadingTypeFromOriginalValueList(registers);

            var accountingPeriod = new Taf1Data(registers, supplier.AnalysisProfile.TariffStages);

            accountingPeriod.SetDate(supplier.AnalysisProfile.BillingPeriod.Start, supplier.AnalysisProfile.BillingPeriod.GetEnd());
            this.SetTotalBillingPeriod(accountingPeriod);

            ValidateBillingPeriod();

            var dayProfiles = supplier.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles;

            foreach (OriginalValueList ovl in originalValueLists)
            {
                var startReading = ovl.MeterReading.GetIntervalReadingFromDate(billingPeriodStart);
                var endReading   = ovl.MeterReading.GetIntervalReadingFromDate(billingPeriodEnd);

                if (startReading == null || !IsStatusValid(startReading))
                {
                    throw new InvalidOperationException($"Zu dem Zeitpunkt {billingPeriodStart} ist kein Wert vorhanden oder der Status kritisch oder fatal.");
                }

                if (endReading == null || !IsStatusValid(endReading))
                {
                    throw new InvalidOperationException($"Zu dem Zeitpunkt {billingPeriodEnd} ist kein Wert vorhanden oder der Status kritisch oder fatal.");
                }

                var dayProfile = this.GetDayProfileNumber(dayProfiles, new ObisId(ovl.MeterReading.ReadingType.ObisCode),
                                                          supplier.AnalysisProfile);

                var tariffStages = supplier.AnalysisProfile.TariffStages;
                var tariffId     = this.GetTariffId(tariffStages, dayProfiles, dayProfile);

                CheckValidSupplierFile(supplier, dayProfile, tariffId);

                var result = this.GetSection(supplier, ovl.MeterReading, startReading, endReading, tariffId);

                accountingPeriod.Add(result);

                accountingPeriod.AddInitialReading(new Reading()
                {
                    Amount   = accountingPeriod.AccountingSections.First(s => s.Reading.ObisCode == ovl.MeterReading.ReadingType.ObisCode).Reading.Amount,
                    ObisCode = new ObisId(ovl.MeterReading.ReadingType.ObisCode)
                });
            }

            return(new TafAdapterData(typeof(Taf2SummaryView), typeof(Taf2DetailView), accountingPeriod));
        }
Example #15
0
        public static UsagePointAdapterTRuDI ParseHanAdapterModel(IEnumerable <XElement> elements)
        {
            UsagePointAdapterTRuDI usagePoint = null;
            var    exceptions            = new List <Exception>();
            var    logEventAlreadyExists = false;
            var    dayIdAlreadyExists    = false;
            string generatorVersion      = null;

            foreach (XElement e in elements)
            {
                switch (e.Name.LocalName)
                {
                case "UsagePoint":
                    usagePoint = new UsagePointAdapterTRuDI()
                    {
                        GeneratorVersion = generatorVersion
                    };
                    break;

                case "GeneratorVersion":
                    generatorVersion = e.Value;
                    break;

                case "usagePointId":
                    usagePoint.UsagePointId = e.Value;
                    break;

                case "tariffName":
                    usagePoint.TariffName = e.Value;
                    break;

                case "Customer":
                    usagePoint.Customer = new Customer();
                    break;

                case "customerId":
                    usagePoint.Customer.CustomerId = e.Value;
                    break;

                case "InvoicingParty":
                    usagePoint.InvoicingParty = new InvoicingParty();
                    break;

                case "invoicingPartyId":
                    usagePoint.InvoicingParty.InvoicingPartyId = e.Value;
                    break;

                case "ServiceCategory":
                    usagePoint.ServiceCategory = new ServiceCategory();
                    break;

                case "kind":
                    usagePoint.ServiceCategory.Kind = (Kind)Convert.ToInt32(e.Value);
                    break;

                case "SMGW":
                    usagePoint.Smgw = new SMGW();
                    break;

                case "certId":
                    if (e.Parent.Name.LocalName == "SMGW")
                    {
                        usagePoint.Smgw.CertIds.Add(Convert.ToByte(e.Value));
                    }
                    else if (e.Parent.Name.LocalName == "Certificate")
                    {
                        usagePoint.Certificates.LastOrDefault().CertId = Convert.ToByte(e.Value);
                    }

                    break;

                case "smgwId":
                    usagePoint.Smgw.SmgwId = e.Value;
                    break;

                case "Certificate":
                    usagePoint.Certificates.Add(new Certificate());
                    break;

                case "certType":
                    usagePoint.Certificates.LastOrDefault().CertType = (CertType)Convert.ToByte(e.Value);
                    break;

                case "parentCertId":
                    usagePoint.Certificates.LastOrDefault().ParentCertId = Convert.ToByte(e.Value);
                    break;

                case "certContent":
                    if (e.Value.ValidateHexString())
                    {
                        usagePoint.Certificates.LastOrDefault().HexStringToByteArray(e.Value);
                    }
                    else
                    {
                        exceptions.Add(new InvalidOperationException("Das Element \"certContent\" enthält keinen gültigen Wert."));
                    }

                    break;

                case "LogEntry":
                    usagePoint.LogEntries.Add(new LogEntry());
                    logEventAlreadyExists = false;
                    break;

                case "recordNumber":
                    usagePoint.LogEntries.LastOrDefault().RecordNumber = Convert.ToUInt32(e.Value);
                    break;

                case "LogEvent":
                    if (logEventAlreadyExists)
                    {
                        exceptions.Add(new InvalidOperationException("The current LogEntry has already a LogEvent instance"));
                    }
                    else
                    {
                        usagePoint.LogEntries.LastOrDefault().LogEvent = new LogEvent();
                        logEventAlreadyExists = true;
                    }

                    break;

                case "level":
                    usagePoint.LogEntries.LastOrDefault().LogEvent.Level = (Level)Convert.ToByte(e.Value);
                    break;

                case "text":
                    usagePoint.LogEntries.LastOrDefault().LogEvent.Text = e.Value;
                    break;

                case "outcome":
                    usagePoint.LogEntries.LastOrDefault().LogEvent.Outcome = (Outcome)Convert.ToByte(e.Value);
                    break;

                case "timestamp":
                    usagePoint.LogEntries.LastOrDefault().LogEvent.Timestamp = Convert.ToDateTime(e.Value);
                    break;

                case "MeterReading":
                    usagePoint.MeterReadings.Add(new MeterReading());
                    usagePoint.MeterReadings.LastOrDefault().UsagePoint = usagePoint;
                    break;

                case "Meter":
                    usagePoint.MeterReadings.LastOrDefault().Meters.Add(new Meter());
                    break;

                case "meterId":
                    usagePoint.MeterReadings.LastOrDefault().Meters.Last().MeterId = e.Value;
                    break;

                case "meterReadingId":
                    usagePoint.MeterReadings.LastOrDefault().MeterReadingId = e.Value;
                    break;

                case "ReadingType":
                    usagePoint.MeterReadings.LastOrDefault().ReadingType = new ReadingType
                    {
                        MeterReading = usagePoint.MeterReadings.LastOrDefault(),
                    };
                    break;

                case "powerOfTenMultiplier":
                    if (e.Parent.Name.LocalName == "ReadingType")
                    {
                        usagePoint.MeterReadings.LastOrDefault()
                        .ReadingType.PowerOfTenMultiplier = (PowerOfTenMultiplier)Convert.ToInt16(e.Value);
                    }

                    break;

                case "uom":
                    usagePoint.MeterReadings.LastOrDefault()
                    .ReadingType.Uom = (Uom)Convert.ToUInt16(e.Value);
                    break;

                case "scaler":
                    usagePoint.MeterReadings.LastOrDefault()
                    .ReadingType.Scaler = Convert.ToSByte(e.Value);
                    break;

                case "obisCode":
                    switch (e.Parent.Name.LocalName)
                    {
                    case "TariffStage":
                        usagePoint.AnalysisProfile.TariffStages.LastOrDefault().ObisCode = e.Value;
                        break;

                    case "ReadingType":
                        usagePoint.MeterReadings.LastOrDefault()
                        .ReadingType.ObisCode = e.Value;
                        break;
                    }
                    break;

                case "qualifiedLogicalName":
                    usagePoint.MeterReadings.LastOrDefault()
                    .ReadingType.QualifiedLogicalName = e.Value;
                    break;

                case "measurementPeriod":
                    usagePoint.MeterReadings.LastOrDefault().ReadingType.MeasurementPeriod = uint.Parse(e.Value);
                    break;

                case "IntervalBlock":
                    usagePoint.MeterReadings.LastOrDefault()
                    .IntervalBlocks.Add(new IntervalBlock());
                    usagePoint.MeterReadings.LastOrDefault()
                    .IntervalBlocks.LastOrDefault()
                    .MeterReading = usagePoint.MeterReadings.LastOrDefault();
                    break;

                case "interval":
                    usagePoint.MeterReadings.LastOrDefault()
                    .IntervalBlocks.LastOrDefault()
                    .Interval = new Interval();
                    break;

                case "duration":
                    switch (e.Parent.Name.LocalName)
                    {
                    case "interval":
                        usagePoint.MeterReadings.LastOrDefault()
                        .IntervalBlocks.LastOrDefault()
                        .Interval.Duration = Convert.ToUInt32(e.Value);
                        break;

                    case "timePeriod":
                        usagePoint.MeterReadings.LastOrDefault()
                        .IntervalBlocks.LastOrDefault()
                        .IntervalReadings.LastOrDefault()
                        .TimePeriod.Duration = Convert.ToUInt32(e.Value);
                        break;

                    case "billingPeriod":
                        usagePoint.AnalysisProfile.BillingPeriod.Duration = Convert.ToUInt32(e.Value);
                        break;
                    }
                    break;

                case "start":
                    switch (e.Parent.Name.LocalName)
                    {
                    case "interval":
                        usagePoint.MeterReadings.LastOrDefault()
                        .IntervalBlocks.LastOrDefault()
                        .Interval.Start = Convert.ToDateTime(e.Value);
                        break;

                    case "timePeriod":
                        usagePoint.MeterReadings.LastOrDefault()
                        .IntervalBlocks.LastOrDefault()
                        .IntervalReadings.LastOrDefault()
                        .TimePeriod.Start = Convert.ToDateTime(e.Value);
                        break;

                    case "billingPeriod":
                        usagePoint.AnalysisProfile.BillingPeriod.Start = Convert.ToDateTime(e.Value);
                        break;
                    }
                    break;

                case "IntervalReading":
                    usagePoint.MeterReadings.LastOrDefault()
                    .IntervalBlocks.LastOrDefault()
                    .IntervalReadings.Add(new IntervalReading());
                    usagePoint.MeterReadings.LastOrDefault()
                    .IntervalBlocks.LastOrDefault()
                    .IntervalReadings.LastOrDefault()
                    .IntervalBlock = usagePoint.MeterReadings.LastOrDefault()
                                     .IntervalBlocks.LastOrDefault();
                    break;

                case "value":
                    usagePoint.MeterReadings.LastOrDefault()
                    .IntervalBlocks.LastOrDefault()
                    .IntervalReadings.LastOrDefault().Value = Convert.ToInt64(e.Value);
                    break;

                case "timePeriod":
                    usagePoint.MeterReadings.LastOrDefault()
                    .IntervalBlocks.LastOrDefault()
                    .IntervalReadings.LastOrDefault().TimePeriod = new Interval();
                    break;

                case "targetTime":
                    usagePoint.MeterReadings.LastOrDefault()
                    .IntervalBlocks.LastOrDefault()
                    .IntervalReadings.LastOrDefault().TargetTime = Convert.ToDateTime(e.Value);

                    usagePoint.MeterReadings.LastOrDefault().IsTargetTimeUsed = true;
                    break;

                case "signature":
                    usagePoint.MeterReadings.LastOrDefault()
                    .IntervalBlocks.LastOrDefault()
                    .IntervalReadings.LastOrDefault().Signature = e.Value;
                    break;

                case "meterSig":
                    usagePoint.MeterReadings.LastOrDefault()
                    .IntervalBlocks.LastOrDefault()
                    .IntervalReadings.LastOrDefault().Signature = e.Value;
                    break;

                case "statusFNN":
                    if (e.Value.ValidateHexString())
                    {
                        usagePoint.MeterReadings.LastOrDefault()
                        .IntervalBlocks.LastOrDefault()
                        .IntervalReadings.LastOrDefault().StatusFNN = new StatusFNN(e.Value);
                    }
                    else
                    {
                        exceptions.Add(new InvalidOperationException("Das Element \"statusFNN\" enthält einen ungültigen Wert."));
                    }
                    break;

                case "statusPTB":
                    usagePoint.MeterReadings.LastOrDefault()
                    .IntervalBlocks.LastOrDefault()
                    .IntervalReadings.LastOrDefault().StatusPTB = (StatusPTB)Convert.ToByte(e.Value);
                    break;

                case "AnalysisProfile":
                    usagePoint.AnalysisProfile = new AnalysisProfile();
                    break;

                case "tariffUseCase":
                    usagePoint.AnalysisProfile.TariffUseCase = (TafId)Convert.ToUInt16(e.Value);
                    break;

                case "tariffId":
                    usagePoint.AnalysisProfile.TariffId = e.Value;
                    break;

                case "defaultTariffNumber":
                    usagePoint.AnalysisProfile.DefaultTariffNumber = Convert.ToUInt16(e.Value);
                    break;

                case "billingPeriod":
                    usagePoint.AnalysisProfile.BillingPeriod = new Interval();
                    break;

                case "TariffStage":
                    usagePoint.AnalysisProfile.TariffStages.Add(new TariffStage());
                    break;

                case "tariffNumber":
                    if (e.Parent.Name.LocalName == "TariffStage")
                    {
                        usagePoint.AnalysisProfile.TariffStages.LastOrDefault().TariffNumber = Convert.ToUInt16(e.Value);
                    }
                    else if (e.Parent.Name.LocalName == "DayTimeProfile")
                    {
                        usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault()
                        .DayTimeProfiles.LastOrDefault().TariffNumber = Convert.ToUInt16(e.Value);
                    }

                    break;

                case "description":
                    usagePoint.AnalysisProfile.TariffStages.LastOrDefault().Description = e.Value;
                    break;

                case "TariffChangeTrigger":
                    usagePoint.AnalysisProfile.TariffChangeTrigger = new TariffChangeTrigger();
                    break;

                case "TimeTrigger":
                    usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger = new TimeTrigger();
                    break;

                case "DayProfile":
                    usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.Add(new DayProfile());
                    dayIdAlreadyExists = false;
                    break;

                case "dayId":
                    if (e.Parent.Name.LocalName == "DayProfile")
                    {
                        if (dayIdAlreadyExists)
                        {
                            exceptions.Add(new InvalidOperationException("Es ist nur ein Element \"dayId\" innerhalb des Elements \"DayProfile\" erlaubt."));
                        }
                        else
                        {
                            usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault()
                            .DayId = Convert.ToUInt16(e.Value);
                            dayIdAlreadyExists = true;
                        }
                    }
                    else if (e.Parent.Name.LocalName == "SpecialDayProfile")
                    {
                        var id = Convert.ToUInt16(e.Value);
                        usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles
                        .LastOrDefault().DayId = id;
                        try
                        {
                            usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles
                            .LastOrDefault().DayProfile = usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger
                                                          .DayProfiles.Single(dp => dp.DayId == id);
                        }
                        catch (Exception ex)
                        {
                            exceptions.Add(ex);
                        }
                    }
                    break;

                case "DayTimeProfile":
                    usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault()
                    .DayTimeProfiles.Add(new DayTimeProfile());
                    usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault()
                    .DayTimeProfiles.LastOrDefault().DayProfile = usagePoint.AnalysisProfile
                                                                  .TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault();
                    break;

                case "startTime":
                    usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault()
                    .DayTimeProfiles.LastOrDefault().StartTime = new TimeVarType();
                    break;

                case "hour":
                    usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault()
                    .DayTimeProfiles.LastOrDefault().StartTime.Hour = Convert.ToByte(e.Value);
                    break;

                case "minute":
                    usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault()
                    .DayTimeProfiles.LastOrDefault().StartTime.Minute = Convert.ToByte(e.Value);
                    break;

                case "second":
                    usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault()
                    .DayTimeProfiles.LastOrDefault().StartTime.Second = Convert.ToByte(e.Value);
                    break;

                case "hundreds":
                    usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles.LastOrDefault()
                    .DayTimeProfiles.LastOrDefault().StartTime.Hundreds = Convert.ToByte(e.Value);
                    break;

                case "SpecialDayProfile":
                    usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles.Add(new SpecialDayProfile());
                    break;

                case "specialDayDate":
                    usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles.LastOrDefault()
                    .SpecialDayDate = new DayVarType();
                    break;

                case "year":
                    usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles.LastOrDefault()
                    .SpecialDayDate.Year = Convert.ToUInt16(e.Value);
                    break;

                case "month":
                    usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles.LastOrDefault()
                    .SpecialDayDate.Month = Convert.ToByte(e.Value);
                    break;

                case "day_of_month":
                    usagePoint.AnalysisProfile.TariffChangeTrigger.TimeTrigger.SpecialDayProfiles.LastOrDefault()
                    .SpecialDayDate.DayOfMonth = Convert.ToByte(e.Value);
                    break;

                case "FirmwareComponent":
                    usagePoint.Smgw.FirmwareComponents.Add(new FirmwareComponent());
                    break;

                case "name":
                    usagePoint.Smgw.FirmwareComponents.Last().Name = e.Value;
                    break;

                case "version":
                    usagePoint.Smgw.FirmwareComponents.Last().Version = e.Value;
                    break;

                case "checksum":
                    usagePoint.Smgw.FirmwareComponents.Last().Checksum = e.Value;
                    break;

                case "FirmwareVersion":
                    usagePoint.Smgw.FirmwareVersion = e.Value;
                    break;

                case "VendorConfig":
                case "tafProfile":
                case "statusVendor":
                case "measurementTimeMeter":
                    // Ignored here: not displayed by TRuDI.
                    break;

                // LogEvent
                case "type":
                case "eventId":
                case "vendorId":
                case "eventSubId":
                case "subjectIdentity":
                case "userIdentity":
                case "eventKindVendor":
                case "secondsIndex":
                case "evidence":
                    break;

                default:
                    if (usagePoint == null)
                    {
                        throw new InvalidOperationException("Keine gültige Datei.");
                    }

                    exceptions.Add(new InvalidOperationException($"Das Element \"{e.Name.LocalName}\" wird nicht unterstützt."));
                    break;
                }
            }

            if (exceptions.Any())
            {
                throw new AggregateException("Han Adapter Parsing error:>", exceptions);
            }

            foreach (var meterReading in usagePoint.MeterReadings)
            {
                meterReading.IntervalBlocks.Sort((a, b) => a.Interval.Start.ToUniversalTime().CompareTo(b.Interval.Start.ToUniversalTime()));
                var measurementPeriod = (int)meterReading.GetMeasurementPeriod().TotalSeconds;

                foreach (var block in meterReading.IntervalBlocks)
                {
                    block.IntervalReadings.Sort((a, b) =>
                    {
                        if (a.TargetTime != null && b.TargetTime != null)
                        {
                            return(a.TargetTime.Value.ToUniversalTime()
                                   .CompareTo(b.TargetTime.Value.ToUniversalTime()));
                        }

                        return(a.TimePeriod.Start.ToUniversalTime()
                               .CompareTo(b.TimePeriod.Start.ToUniversalTime()));
                    });

                    if (meterReading.IsOriginalValueList())
                    {
                        foreach (var ir in block.IntervalReadings)
                        {
                            if (ir.TargetTime == null)
                            {
                                if (measurementPeriod > 0)
                                {
                                    ir.TargetTime = ModelExtensions.GetAlignedTimestamp(
                                        ir.TimePeriod.Start,
                                        measurementPeriod,
                                        3);
                                }
                                else
                                {
                                    ir.TargetTime = ir.TimePeriod.Start;
                                }
                            }
                        }
                    }
                }
            }

            if (usagePoint?.LogEntries != null && usagePoint.LogEntries.Any())
            {
                usagePoint.LogEntries.Sort((a, b) =>
                {
                    if (a.RecordNumber != null && b.RecordNumber != null)
                    {
                        return(a.RecordNumber.Value.CompareTo(b.RecordNumber.Value));
                    }

                    return(a.LogEvent.Timestamp.ToUniversalTime()
                           .CompareTo(b.LogEvent.Timestamp.ToUniversalTime()));
                });
            }

            return(usagePoint);
        }
Example #16
0
        /// <inheritdoc />
        /// <summary>
        /// Calculates the derived registers for Taf2.
        /// </summary>
        /// <param name="device">Data from the SMGW. There should be just original value lists.</param>
        /// <param name="supplier">The calculation data from the supplier.</param>
        /// <returns>An ITaf2Data instance. The object contains the calculated data.</returns>
        public TafAdapterData Calculate(UsagePointAdapterTRuDI device, UsagePointLieferant supplier)
        {
            this.originalValueLists =
                device.MeterReadings.Where(mr => mr.IsOriginalValueList()).Select(mr => new OriginalValueList(mr, device.ServiceCategory.Kind ?? Kind.Electricity)).ToList();

            if (!this.originalValueLists.Any())
            {
                throw new InvalidOperationException("Es ist keine originäre Messwertliste verfügbar.");
            }

            var registers = supplier.GetRegister();

            this.UpdateReadingTypeFromOriginalValueList(registers);

            var accountingPeriod = new Taf2Data(registers, supplier.AnalysisProfile.TariffStages);
            var dayProfiles      = supplier.AnalysisProfile.TariffChangeTrigger.TimeTrigger.DayProfiles;

            foreach (var ovl in this.originalValueLists)
            {
                var bpStart = ovl.MeterReading.GetFirstReadingTimestamp(supplier.AnalysisProfile.BillingPeriod.Start, supplier.AnalysisProfile.BillingPeriod.GetEnd());
                var bpEnd   = ovl.MeterReading.GetLastReadingTimestamp(supplier.AnalysisProfile.BillingPeriod.Start, supplier.AnalysisProfile.BillingPeriod.GetEnd());
                if (bpEnd == null || bpStart == null || bpStart == bpEnd)
                {
                    throw new InvalidOperationException("Keine Messwerte innerhalb des Abbrechnungszeitraums gefunden.");
                }

                accountingPeriod.SetDates(bpStart.Value, bpEnd.Value);
                this.SetTotalBillingPeriod(accountingPeriod);

                var    validDayProfiles   = dayProfiles.GetValidDayProfilesForMeterReading(ovl.Obis, supplier.AnalysisProfile.TariffStages);
                var    specialDayProfiles = this.GetSpecialDayProfiles(supplier, validDayProfiles, accountingPeriod.Begin, accountingPeriod.End);
                long   latestReading      = 0;
                ushort latestTariffId     = 63;

                // Check if the lists validDayProfiles and special DayProfiles are null or empty
                if (!this.CheckUsedLists(validDayProfiles, specialDayProfiles))
                {
                    continue;
                }

                // Calculation of the single days (latestReading and latestTariffId are needed for days across gap detection)
                foreach (SpecialDayProfile profile in specialDayProfiles)
                {
                    var currentDayData = this.GetDayData(profile, dayProfiles, ovl.MeterReading, supplier, latestReading, latestTariffId);
                    if (!(currentDayData.day.Start == DateTime.MinValue) || currentDayData.day.MeasuringRanges.Count != 0)
                    {
                        accountingPeriod.Add(currentDayData.day);
                    }
                    latestReading  = currentDayData.latestReading;
                    latestTariffId = currentDayData.tariffId;
                }

                // Set the initial overall meter reading
                accountingPeriod.AddInitialReading(new Reading()
                {
                    Amount   = accountingPeriod.AccountingSections.First().Reading.Amount,
                    ObisCode = ovl.Obis
                });
            }

            accountingPeriod.OrderSections();
            return(new TafAdapterData(typeof(Taf2SummaryView), typeof(Taf2DetailView), accountingPeriod));
        }