From ea5af0dca3a0ee36a741c2c9e84820fa48f60efa Mon Sep 17 00:00:00 2001 From: Thomas Godon Date: Tue, 10 Jan 2023 00:07:15 +0100 Subject: [PATCH 1/3] add belgian obsi code support --- DSMRParser.Tests/DSMRParser.Tests.csproj | 3 ++ DSMRParser.Tests/TelegramParserTests.cs | 54 ++++++++++++++++++++++ DSMRParser.Tests/testdata/v5_02_flu_ok.txt | 28 +++++++++++ DSMRParser/BellgianOBISRegistry.cs | 16 +++++++ DSMRParser/Models/Telegram.cs | 14 +++--- 5 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 DSMRParser.Tests/testdata/v5_02_flu_ok.txt create mode 100644 DSMRParser/BellgianOBISRegistry.cs diff --git a/DSMRParser.Tests/DSMRParser.Tests.csproj b/DSMRParser.Tests/DSMRParser.Tests.csproj index 6137dce..9b7cd82 100644 --- a/DSMRParser.Tests/DSMRParser.Tests.csproj +++ b/DSMRParser.Tests/DSMRParser.Tests.csproj @@ -35,6 +35,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/DSMRParser.Tests/TelegramParserTests.cs b/DSMRParser.Tests/TelegramParserTests.cs index 03c0c43..1963e48 100644 --- a/DSMRParser.Tests/TelegramParserTests.cs +++ b/DSMRParser.Tests/TelegramParserTests.cs @@ -242,4 +242,58 @@ public void DSMRTelegramParser_Reads_V5_Telegrams() Assert.AreEqual(11223.322m, telegram.SlaveDelivered!.Value!.Value); Assert.AreEqual(OBISUnit.kWh, telegram.SlaveDelivered!.Value!.Unit); } + + [TestMethod] + public void DSMRTelegramParser_Reads_V5_0_2_Flu_Telegrams() + { + var target = new DSMRTelegramParser(); + var telegram = target.Parse(File.ReadAllBytes(@"testdata\v5_02_flu_ok.txt")); + Assert.AreEqual(@"FLU5\253770234_A", telegram.Identification); + Assert.AreEqual(50217, telegram.DSMRVersion); + Assert.AreEqual("K8EG004046395507", telegram.EquipmentId); + Assert.AreEqual(new DateTimeOffset(2023, 01, 8, 22, 29, 30, TimeSpan.FromHours(1)), telegram.TimeStamp); + + Assert.AreEqual(3540.994m, telegram.EnergyDeliveredTariff1!.Value); + Assert.AreEqual(OBISUnit.kWh, telegram.EnergyDeliveredTariff1!.Unit); + Assert.AreEqual(4343.832m, telegram.EnergyDeliveredTariff2!.Value); + Assert.AreEqual(OBISUnit.kWh, telegram.EnergyDeliveredTariff2!.Unit); + Assert.AreEqual(447.900m, telegram.EnergyReturnedTariff1!.Value); + Assert.AreEqual(OBISUnit.kWh, telegram.EnergyReturnedTariff1!.Unit); + Assert.AreEqual(203.828m, telegram.EnergyReturnedTariff2!.Value); + Assert.AreEqual(OBISUnit.kWh, telegram.EnergyReturnedTariff2!.Unit); + + Assert.AreEqual(2, telegram.ElectricityTariff); + + // TODO: add Current average demand - Active energy import + // TODO: Maximum demand – Active energy import of the running month + // TODO: Maximum demand – Active energy import of the last 13 months + + Assert.AreEqual(0.544m, telegram.PowerDelivered!.Value); + Assert.AreEqual(OBISUnit.kW, telegram.PowerDelivered!.Unit); + Assert.AreEqual(0.0m, telegram.PowerReturned!.Value); + Assert.AreEqual(OBISUnit.kW, telegram.PowerDelivered!.Unit); + + Assert.AreEqual(0.544m, telegram.PowerDeliveredL1!.Value); + Assert.AreEqual(OBISUnit.kW, telegram.PowerDeliveredL1!.Unit); + Assert.AreEqual(0.0m, telegram.PowerReturnedL1!.Value); + Assert.AreEqual(OBISUnit.kW, telegram.PowerReturnedL1!.Unit); + + Assert.AreEqual(231.5m, telegram.VoltageL1!.Value); + Assert.AreEqual(OBISUnit.V, telegram.VoltageL1!.Unit); + + Assert.AreEqual(2.85m, telegram.CurrentL1!.Value); + Assert.AreEqual(OBISUnit.A, telegram.CurrentL1!.Unit); + + // TODO: add breaker state + // TODO: add limiter threshold + // TODO: add Fuse supervision threshold + + Assert.AreEqual(string.Empty, telegram.MessageLong); + Assert.AreEqual(3, telegram.GasDeviceType); + Assert.AreEqual("9999ABCD123456789", telegram.GasEquipmentId); + Assert.AreEqual(1, telegram.GasValvePosition); + Assert.AreEqual(new DateTimeOffset(2023, 01, 8, 22, 25, 01, TimeSpan.FromHours(1)), telegram.GasDelivered!.DateTime!.Value); + Assert.AreEqual(4856.664m, telegram.GasDelivered!.Value!.Value); + Assert.AreEqual(OBISUnit.m3, telegram.GasDelivered!.Value!.Unit); + } } \ No newline at end of file diff --git a/DSMRParser.Tests/testdata/v5_02_flu_ok.txt b/DSMRParser.Tests/testdata/v5_02_flu_ok.txt new file mode 100644 index 0000000..8943d2e --- /dev/null +++ b/DSMRParser.Tests/testdata/v5_02_flu_ok.txt @@ -0,0 +1,28 @@ +/FLU5\253770234_A + +0-0:96.1.4(50217) +0-0:96.1.1(4B384547303034303436333935353037) +0-0:1.0.0(230108222930W) +1-0:1.8.1(003540.994*kWh) +1-0:1.8.2(004343.832*kWh) +1-0:2.8.1(000447.900*kWh) +1-0:2.8.2(000203.828*kWh) +0-0:96.14.0(0002) +1-0:1.4.0(00.554*kW) +1-0:1.6.0(230107171500W)(02.572*kW) +0-0:98.1.0(1)(1-0:1.6.0)(1-0:1.6.0)(230101000000W)(221229143000W)(04.875*kW) +1-0:1.7.0(00.544*kW) +1-0:2.7.0(00.000*kW) +1-0:21.7.0(00.544*kW) +1-0:22.7.0(00.000*kW) +1-0:32.7.0(231.5*V) +1-0:31.7.0(002.85*A) +0-0:96.3.10(1) +0-0:17.0.0(999.9*kW) +1-0:31.4.0(999*A) +0-0:96.13.0() +0-1:24.1.0(003) +0-1:96.1.1(3939393941424344313233343536373839) +0-1:24.4.0(1) +0-1:24.2.3(230108222501W)(04856.664*m3) +!7450 diff --git a/DSMRParser/BellgianOBISRegistry.cs b/DSMRParser/BellgianOBISRegistry.cs new file mode 100644 index 0000000..ecb74fa --- /dev/null +++ b/DSMRParser/BellgianOBISRegistry.cs @@ -0,0 +1,16 @@ +using DSMRParser.Models; + +namespace DSMRParser; + +/// +/// OBIS registry of known s found in belgian DSMR s. +/// +public static class BelgianOBISRegistry +{ + /// The version of the DSMR telegram. + public static readonly OBISDescriptor DSMRVersion = new() { Id = new OBISId(0, 0, 96, 1, 4), Description = "DSMR version" }; + /// Gas equipment identifier. + public static readonly OBISDescriptor GasEquipmentId = new() { Id = new OBISId(0, 1, 96, 1, 1), Description = "Gas equipment id" }; + /// Gas delivered. + public static readonly OBISDescriptor GasDelivered = new() { Id = new OBISId(0, 1, 24, 2, 3), Description = "Gas delivered", Unit = OBISUnit.m3 }; +} \ No newline at end of file diff --git a/DSMRParser/Models/Telegram.cs b/DSMRParser/Models/Telegram.cs index 56583e2..5b31a9b 100644 --- a/DSMRParser/Models/Telegram.cs +++ b/DSMRParser/Models/Telegram.cs @@ -31,7 +31,7 @@ public class Telegram /// Gets the identification of the DSMR meter the telegram originated from. public string? Identification { get; init; } /// Gets the version of the DSMR telegram. - public int? DSMRVersion => ParseInt(OBISRegistry.DSMRVersion); + public int? DSMRVersion => ParseInt(OBISRegistry.DSMRVersion) ?? ParseInt(BelgianOBISRegistry.DSMRVersion); /// Gets the timestamp of the DSMR telegram. public DateTimeOffset? TimeStamp => ParseTimeStamp(OBISRegistry.TimeStamp); /// Equipment identifier. @@ -83,11 +83,11 @@ public class Telegram /// Instantaneous voltage L3. public UnitValue? VoltageL3 => ParseDecimalUnit(OBISRegistry.VoltageL3); /// Instantaneous current L1. - public UnitValue? CurrentL1 => ParseIntUnit(OBISRegistry.CurrentL1); + public UnitValue? CurrentL1 => ParseDecimalUnit(OBISRegistry.CurrentL1); /// Instantaneous current L2. - public UnitValue? CurrentL2 => ParseIntUnit(OBISRegistry.CurrentL2); + public UnitValue? CurrentL2 => ParseDecimalUnit(OBISRegistry.CurrentL2); /// Instantaneous current L3. - public UnitValue? CurrentL3 => ParseIntUnit(OBISRegistry.CurrentL3); + public UnitValue? CurrentL3 => ParseDecimalUnit(OBISRegistry.CurrentL3); /// Instantaneous active power L1. public UnitValue? PowerDeliveredL1 => ParseDecimalUnit(OBISRegistry.PowerDeliveredL1); /// Instantaneous active power L2. @@ -103,12 +103,14 @@ public class Telegram /// Gas devicetype. public int? GasDeviceType => ParseInt(OBISRegistry.GasDeviceType); /// Gas equipment identifier. - public string? GasEquipmentId => DecodeString(GetByDescriptor(OBISRegistry.GasEquipmentId)); + public string? GasEquipmentId => DecodeString(GetByDescriptor(OBISRegistry.GasEquipmentId)) ?? DecodeString(GetByDescriptor(BelgianOBISRegistry.GasEquipmentId)); /// Gas valve position. public int? GasValvePosition => ParseInt(OBISRegistry.GasValvePosition); + /// Gas delivered. public TimeStampedValue>? GasDelivered => - ParseTimeStampedValues(OBISRegistry.GasDelivered, (d, v) => ParseDecimalUnit(d, v)).FirstOrDefault(); + ParseTimeStampedValues(OBISRegistry.GasDelivered, ParseDecimalUnit).FirstOrDefault() ?? + ParseTimeStampedValues(BelgianOBISRegistry.GasDelivered, ParseDecimalUnit).FirstOrDefault(); /// Gas delivered - OLD (pre-V4). public TimeStampedValue>? GasDeliveredOld => From 05cc2771de375f48204c905976b472e4d2f94af0 Mon Sep 17 00:00:00 2001 From: Thomas Godon Date: Tue, 10 Jan 2023 00:09:00 +0100 Subject: [PATCH 2/3] type filename --- DSMRParser/{BellgianOBISRegistry.cs => BelgianOBISRegistry.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename DSMRParser/{BellgianOBISRegistry.cs => BelgianOBISRegistry.cs} (100%) diff --git a/DSMRParser/BellgianOBISRegistry.cs b/DSMRParser/BelgianOBISRegistry.cs similarity index 100% rename from DSMRParser/BellgianOBISRegistry.cs rename to DSMRParser/BelgianOBISRegistry.cs From e12c33a488e7dc4ad2162a8b10d21c06b2aa7b5d Mon Sep 17 00:00:00 2001 From: Thomas Godon Date: Tue, 19 Mar 2024 22:04:45 +0100 Subject: [PATCH 3/3] read peak power (#1) --- DSMRParser.Tests/TelegramParserTests.cs | 9 +++++++-- DSMRParser/BelgianOBISRegistry.cs | 4 ++++ DSMRParser/Models/Telegram.cs | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/DSMRParser.Tests/TelegramParserTests.cs b/DSMRParser.Tests/TelegramParserTests.cs index 5daebfb..8819f57 100644 --- a/DSMRParser.Tests/TelegramParserTests.cs +++ b/DSMRParser.Tests/TelegramParserTests.cs @@ -264,8 +264,13 @@ public void DSMRTelegramParser_Reads_V5_0_2_Flu_Telegrams() Assert.AreEqual(2, telegram.ElectricityTariff); - // TODO: add Current average demand - Active energy import - // TODO: Maximum demand – Active energy import of the running month + Assert.AreEqual(OBISUnit.kW, telegram.PowerDeliveredCurrentAvg!.Unit); + Assert.AreEqual(0.554m, telegram.PowerDeliveredCurrentAvg!.Value); + + Assert.AreEqual(new DateTimeOffset(2023, 01, 7, 17, 15, 00, TimeSpan.FromHours(1)), telegram.EnergyDeliveredMaxRunningMonth!.DateTime); + Assert.AreEqual(OBISUnit.kW, telegram.EnergyDeliveredMaxRunningMonth!.Value!.Unit); + Assert.AreEqual(2.572m, telegram.EnergyDeliveredMaxRunningMonth!.Value!.Value); + // TODO: Maximum demand – Active energy import of the last 13 months Assert.AreEqual(0.544m, telegram.PowerDelivered!.Value); diff --git a/DSMRParser/BelgianOBISRegistry.cs b/DSMRParser/BelgianOBISRegistry.cs index ecb74fa..de434cf 100644 --- a/DSMRParser/BelgianOBISRegistry.cs +++ b/DSMRParser/BelgianOBISRegistry.cs @@ -13,4 +13,8 @@ public static class BelgianOBISRegistry public static readonly OBISDescriptor GasEquipmentId = new() { Id = new OBISId(0, 1, 96, 1, 1), Description = "Gas equipment id" }; /// Gas delivered. public static readonly OBISDescriptor GasDelivered = new() { Id = new OBISId(0, 1, 24, 2, 3), Description = "Gas delivered", Unit = OBISUnit.m3 }; + /// Peak power current month. + public static readonly OBISDescriptor PowerMaxCurrentAverage = new() { Id = new OBISId(1, 0, 1, 4, 0), Description = "Current average demand - active energy import", Unit = OBISUnit.kW }; + /// Peak power current month. + public static readonly OBISDescriptor PowerDeliveredMaxRunningMonth = new() { Id = new OBISId(1, 0, 1, 6, 0), Description = "Peak power running Month", Unit = OBISUnit.kW}; } \ No newline at end of file diff --git a/DSMRParser/Models/Telegram.cs b/DSMRParser/Models/Telegram.cs index d8bb763..0ff8613 100644 --- a/DSMRParser/Models/Telegram.cs +++ b/DSMRParser/Models/Telegram.cs @@ -48,10 +48,14 @@ public class Telegram(string? identification, IEnumerable<(OBISId obisid, IEnume public UnitValue? EnergyReturnedTariff1 => ParseDecimalUnit(OBISRegistry.EnergyReturnedTariff1); /// Electricity returned (Tariff 2). public UnitValue? EnergyReturnedTariff2 => ParseDecimalUnit(OBISRegistry.EnergyReturnedTariff2); + /// Instantaneous energy delivered max running month. + public TimeStampedValue>? EnergyDeliveredMaxRunningMonth => ParseTimeStampedValues(BelgianOBISRegistry.PowerDeliveredMaxRunningMonth, ParseDecimalUnit).FirstOrDefault(); /// Tariff indicator electricity. public int? ElectricityTariff => ParseInt(OBISRegistry.ElectricityTariff); /// Actual electricity power delivered. public UnitValue? PowerDelivered => ParseDecimalUnit(OBISRegistry.PowerDelivered); + /// Actual electricity power delivered average. + public UnitValue? PowerDeliveredCurrentAvg => ParseDecimalUnit(BelgianOBISRegistry.PowerMaxCurrentAverage); /// Actual electricity power returned. public UnitValue? PowerReturned => ParseDecimalUnit(OBISRegistry.PowerReturned); /// The actual threshold Electricity.