Skip to content

Add Belgian (Fluvius) OBIS code support #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
38 changes: 20 additions & 18 deletions DSMRParser.Tests/DSMRParser.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,24 @@
<ProjectReference Include="..\DSMRParser\DSMRParser.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="testdata\v2_2_mangled.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="testdata\v2_2_ok.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="testdata\v3_ok.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="testdata\v4_2_ok.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="testdata\v5_ok.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
<None Update="testdata\v2_2_mangled.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="testdata\v2_2_ok.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="testdata\v3_ok.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="testdata\v4_2_ok.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="testdata\v5_02_flu_ok.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="testdata\v5_ok.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
59 changes: 59 additions & 0 deletions DSMRParser.Tests/TelegramParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,4 +242,63 @@ 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);

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);
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);
}
}
28 changes: 28 additions & 0 deletions DSMRParser.Tests/testdata/v5_02_flu_ok.txt
Original file line number Diff line number Diff line change
@@ -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
20 changes: 20 additions & 0 deletions DSMRParser/BelgianOBISRegistry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using DSMRParser.Models;

namespace DSMRParser;

/// <summary>
/// OBIS registry of known <see cref="OBISDescriptor"/>s found in belgian DSMR <see cref="Telegram"/>s.
/// </summary>
public static class BelgianOBISRegistry
{
/// <summary>The version of the DSMR telegram.</summary>
public static readonly OBISDescriptor DSMRVersion = new() { Id = new OBISId(0, 0, 96, 1, 4), Description = "DSMR version" };
/// <summary>Gas equipment identifier.</summary>
public static readonly OBISDescriptor GasEquipmentId = new() { Id = new OBISId(0, 1, 96, 1, 1), Description = "Gas equipment id" };
/// <summary>Gas delivered.</summary>
public static readonly OBISDescriptor GasDelivered = new() { Id = new OBISId(0, 1, 24, 2, 3), Description = "Gas delivered", Unit = OBISUnit.m3 };
/// <summary>Peak power current month.</summary>
public static readonly OBISDescriptor PowerMaxCurrentAverage = new() { Id = new OBISId(1, 0, 1, 4, 0), Description = "Current average demand - active energy import", Unit = OBISUnit.kW };
/// <summary>Peak power current month.</summary>
public static readonly OBISDescriptor PowerDeliveredMaxRunningMonth = new() { Id = new OBISId(1, 0, 1, 6, 0), Description = "Peak power running Month", Unit = OBISUnit.kW};
}
18 changes: 12 additions & 6 deletions DSMRParser/Models/Telegram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class Telegram(string? identification, IEnumerable<(OBISId obisid, IEnume
/// <summary>Gets the identification of the DSMR meter the telegram originated from.</summary>
public string? Identification { get; init; } = identification ?? throw new ArgumentNullException(nameof(identification));
/// <summary>Gets the version of the DSMR telegram.</summary>
public int? DSMRVersion => ParseInt(OBISRegistry.DSMRVersion);
public int? DSMRVersion => ParseInt(OBISRegistry.DSMRVersion) ?? ParseInt(BelgianOBISRegistry.DSMRVersion);
/// <summary>Gets the timestamp of the DSMR telegram.</summary>
public DateTimeOffset? TimeStamp => ParseTimeStamp(OBISRegistry.TimeStamp);
/// <summary>Equipment identifier.</summary>
Expand All @@ -48,10 +48,14 @@ public class Telegram(string? identification, IEnumerable<(OBISId obisid, IEnume
public UnitValue<decimal>? EnergyReturnedTariff1 => ParseDecimalUnit(OBISRegistry.EnergyReturnedTariff1);
/// <summary>Electricity returned (Tariff 2).</summary>
public UnitValue<decimal>? EnergyReturnedTariff2 => ParseDecimalUnit(OBISRegistry.EnergyReturnedTariff2);
/// <summary>Instantaneous energy delivered max running month.</summary>
public TimeStampedValue<UnitValue<decimal>>? EnergyDeliveredMaxRunningMonth => ParseTimeStampedValues(BelgianOBISRegistry.PowerDeliveredMaxRunningMonth, ParseDecimalUnit).FirstOrDefault();
/// <summary>Tariff indicator electricity.</summary>
public int? ElectricityTariff => ParseInt(OBISRegistry.ElectricityTariff);
/// <summary>Actual electricity power delivered.</summary>
public UnitValue<decimal>? PowerDelivered => ParseDecimalUnit(OBISRegistry.PowerDelivered);
/// <summary>Actual electricity power delivered average.</summary>
public UnitValue<decimal>? PowerDeliveredCurrentAvg => ParseDecimalUnit(BelgianOBISRegistry.PowerMaxCurrentAverage);
/// <summary>Actual electricity power returned.</summary>
public UnitValue<decimal>? PowerReturned => ParseDecimalUnit(OBISRegistry.PowerReturned);
/// <summary>The actual threshold Electricity.</summary>
Expand Down Expand Up @@ -87,11 +91,11 @@ public class Telegram(string? identification, IEnumerable<(OBISId obisid, IEnume
/// <summary>Instantaneous voltage L3.</summary>
public UnitValue<decimal>? VoltageL3 => ParseDecimalUnit(OBISRegistry.VoltageL3);
/// <summary>Instantaneous current L1.</summary>
public UnitValue<int>? CurrentL1 => ParseIntUnit(OBISRegistry.CurrentL1);
public UnitValue<decimal>? CurrentL1 => ParseDecimalUnit(OBISRegistry.CurrentL1);
/// <summary>Instantaneous current L2.</summary>
public UnitValue<int>? CurrentL2 => ParseIntUnit(OBISRegistry.CurrentL2);
public UnitValue<decimal>? CurrentL2 => ParseDecimalUnit(OBISRegistry.CurrentL2);
/// <summary>Instantaneous current L3.</summary>
public UnitValue<int>? CurrentL3 => ParseIntUnit(OBISRegistry.CurrentL3);
public UnitValue<decimal>? CurrentL3 => ParseDecimalUnit(OBISRegistry.CurrentL3);
/// <summary>Instantaneous active power L1.</summary>
public UnitValue<decimal>? PowerDeliveredL1 => ParseDecimalUnit(OBISRegistry.PowerDeliveredL1);
/// <summary>Instantaneous active power L2.</summary>
Expand All @@ -107,12 +111,14 @@ public class Telegram(string? identification, IEnumerable<(OBISId obisid, IEnume
/// <summary>Gas devicetype.</summary>
public int? GasDeviceType => ParseInt(OBISRegistry.GasDeviceType);
/// <summary>Gas equipment identifier.</summary>
public string? GasEquipmentId => DecodeString(GetByDescriptor(OBISRegistry.GasEquipmentId));
public string? GasEquipmentId => DecodeString(GetByDescriptor(OBISRegistry.GasEquipmentId)) ?? DecodeString(GetByDescriptor(BelgianOBISRegistry.GasEquipmentId));
/// <summary>Gas valve position.</summary>
public int? GasValvePosition => ParseInt(OBISRegistry.GasValvePosition);

/// <summary>Gas delivered.</summary>
public TimeStampedValue<UnitValue<decimal>>? GasDelivered =>
ParseTimeStampedValues(OBISRegistry.GasDelivered, ParseDecimalUnit).FirstOrDefault();
ParseTimeStampedValues(OBISRegistry.GasDelivered, ParseDecimalUnit).FirstOrDefault() ??
ParseTimeStampedValues(BelgianOBISRegistry.GasDelivered, ParseDecimalUnit).FirstOrDefault();

/// <summary>Gas delivered - OLD (pre-V4).</summary>
public TimeStampedValue<UnitValue<decimal>>? GasDeliveredOld =>
Expand Down