diff --git a/TestApp/EnergyManager.cs b/TestApp/EnergyManager.cs new file mode 100644 index 0000000..6e472e3 --- /dev/null +++ b/TestApp/EnergyManager.cs @@ -0,0 +1,260 @@ +using MQTTnet; +using MQTTnet.Client; +using System.Collections.Immutable; +using System.Runtime.CompilerServices; + +namespace TestApp +{ + internal class EnergyManager + { + private MqttFactory _MqttFactory; + private IMqttClient _MqttClient; + + private ImmutableDictionary _CurrentValues = ImmutableDictionary.Empty; + + private EnergyManager() + { + _MqttFactory= new MqttFactory(); + _MqttClient = _MqttFactory.CreateMqttClient(); + } + + public static async Task Create() + { + var ret = new EnergyManager(); + await ret.Connect(); + return ret; + } + + private async Task Connect() { + var clientOptions = new MqttClientOptionsBuilder() + .WithTcpServer("localhost") + .Build(); + + await _MqttClient.ConnectAsync(clientOptions); + + _MqttClient.ApplicationMessageReceivedAsync += Client_ApplicationMessageReceivedAsync; + + var subscribeOptions = _MqttFactory.CreateSubscribeOptionsBuilder() + .WithTopicFilter( + f => { + f.WithTopic("gdr/local/values/smart-meter"); + } + ) + .Build(); + + var response = await _MqttClient.SubscribeAsync(subscribeOptions); + } + + private Task Client_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg) + { + switch (arg.ApplicationMessage.Topic) + { + case "gdr/local/values/smart-meter": + ParseGDRs(arg.ApplicationMessage.Payload); + break; + } + + return Task.CompletedTask; + } + + private void ParseGDRs(byte[] payload) + { + var gdrs = GDRs.Parser.ParseFrom(payload); + + if (!gdrs.GDRs_.TryGetValue("smart-meter", out GDR smartMeterGDR)) + { + return; + } + + _CurrentValues = smartMeterGDR.Values.ToImmutableDictionary(); + } + + private double GetValue(ulong obisCode, double factor) + { + if (!_CurrentValues.TryGetValue(obisCode, out ulong value)) + { + return double.NaN; + } + + return factor * value; + } + + /// in W + public double ActivePowerPositive => GetValue(1099528667391UL, 0.001); + + /// in Wh + public double ActiveEnergyPositive => GetValue(1099528929535UL, 0.001); + + /// in W + public double ActivePowerNegative => GetValue(1099545444607UL, 0.001); + + /// in Wh + public double ActiveEnergyNegative => GetValue(1099545706751UL, 0.001); + + /// in var + public double ReactivePowerPositive => GetValue(1099562221823UL, 0.001); + + /// in varh + public double ReactiveEnergyPositive => GetValue(1099562483967UL, 0.001); + + /// in var + public double ReactivePowerNegative => GetValue(1099578999039UL, 0.001); + + /// in varh + public double ReactiveEnergyNegative => GetValue(1099579261183UL, 0.001); + + /// in VA + public double ApparentPowerPositive => GetValue(1099662885119UL, 0.001); + + /// in VAh + public double ApparentEnergyPositive => GetValue(1099663147263UL, 0.001); + + /// in VA + public double ApparentPowerNegative => GetValue(1099679662335UL, 0.001); + + /// in VAh + public double ApparentEnergyNegative => GetValue(1099679924479UL, 0.001); + + /// in - + public double PowerFactor => GetValue(1099729993983UL, 0.001); + + /// in Hz + public double SupplyFrequency => GetValue(1099746771199UL, 0.001); + + /// in W + public double ActivePowerPositiveL1 => GetValue(1099864211711UL, 0.001); + + /// in Wh + public double ActiveEnergyPositiveL1 => GetValue(1099864473855UL, 0.001); + + /// in W + public double ActivePowerNegativeL1 => GetValue(1099880988927UL, 0.001); + + /// in Wh + public double ActiveEnergyNegativeL1 => GetValue(1099881251071UL, 0.001); + + /// in var + public double ReactivePowerPositiveL1 => GetValue(1099897766143UL, 0.001); + + /// in varh + public double ReactiveEnergyPositiveL1 => GetValue(1099898028287UL, 0.001); + + /// in var + public double ReactivePowerNegativeL1 => GetValue(1099914543359UL, 0.001); + + /// in varh + public double ReactiveEnergyNegativeL1 => GetValue(1099914805503UL, 0.001); + + /// in VA + public double ApparentPowerPositiveL1 => GetValue(1099998429439UL, 0.001); + + /// in VAh + public double ApparentEnergyPositiveL1 => GetValue(1099998691583UL, 0.001); + + /// in VA + public double ApparentPowerNegativeL1 => GetValue(1100015206655UL, 0.001); + + /// in VAh + public double ApparentEnergyNegativeL1 => GetValue(1100015468799UL, 0.001); + + /// in A + public double CurrentL1 => GetValue(1100031983871UL, 0.001); + + /// in V + public double VoltageL1 => GetValue(1100048761087UL, 0.001); + + /// in - + public double PowerFactorL1 => GetValue(1100065538303UL, 0.001); + + /// in W + public double ActivePowerPositiveL2 => GetValue(1100199756031UL, 0.001); + + /// in Wh + public double ActiveEnergyPositiveL2 => GetValue(1100200018175UL, 0.001); + + /// in W + public double ActivePowerNegativeL2 => GetValue(1100216533247UL, 0.001); + + /// in Wh + public double ActiveEnergyNegativeL2 => GetValue(1100216795391UL, 0.001); + + /// in var + public double ReactivePowerPositiveL2 => GetValue(1100233310463UL, 0.001); + + /// in varh + public double ReactiveEnergyPositiveL2 => GetValue(1100233572607UL, 0.001); + + /// in var + public double ReactivePowerNegativeL2 => GetValue(1100250087679UL, 0.001); + + /// in varh + public double ReactiveEnergyNegativeL2 => GetValue(1100250349823UL, 0.001); + + /// in VA + public double ApparentPowerPositiveL2 => GetValue(1100333973759UL, 0.001); + + /// in VAh + public double ApparentEnergyPositiveL2 => GetValue(1100334235903UL, 0.001); + + /// in VA + public double ApparentPowerNegativeL2 => GetValue(1100350750975UL, 0.001); + + /// in VAh + public double ApparentEnergyNegativeL2 => GetValue(1100351013119UL, 0.001); + + /// in A + public double CurrentL2 => GetValue(1100367528191UL, 0.001); + + /// in V + public double VoltageL2 => GetValue(1100384305407UL, 0.001); + + /// in - + public double PowerFactorL2 => GetValue(1100401082623UL, 0.001); + + /// in W + public double ActivePowerPositiveL3 => GetValue(1100535300351UL, 0.001); + + /// in Wh + public double ActiveEnergyPositiveL3 => GetValue(1100535562495UL, 0.001); + + /// in W + public double ActivePowerNegativeL3 => GetValue(1100552077567UL, 0.001); + + /// in Wh + public double ActiveEnergyNegativeL3 => GetValue(1100552339711UL, 0.001); + + /// in var + public double ReactivePowerPositiveL3 => GetValue(1100568854783UL, 0.001); + + /// in varh + public double ReactiveEnergyPositiveL3 => GetValue(1100569116927UL, 0.001); + + /// in var + public double ReactivePowerNegativeL3 => GetValue(1100585631999UL, 0.001); + + /// in varh + public double ReactiveEnergyNegativeL3 => GetValue(1100585894143UL, 0.001); + + /// in VA + public double ApparentPowerPositiveL3 => GetValue(1100669518079UL, 0.001); + + /// in VAh + public double ApparentEnergyPositiveL3 => GetValue(1100669780223UL, 0.001); + + /// in VA + public double ApparentPowerNegativeL3 => GetValue(1100686295295UL, 0.001); + + /// in VAh + public double ApparentEnergyNegativeL3 => GetValue(1100686557439UL, 0.001); + + /// in A + public double CurrentL3 => GetValue(1100703072511UL, 0.001); + + /// in V + public double VoltageL3 => GetValue(1100719849727UL, 0.001); + + /// in - + public double PowerFactorL3 => GetValue(1100736626943UL, 0.001); + + } +} diff --git a/TestApp/Program.cs b/TestApp/Program.cs index fc549b0..c04dc75 100644 --- a/TestApp/Program.cs +++ b/TestApp/Program.cs @@ -1,18 +1,16 @@ -using MQTTnet; -using MQTTnet.Client; -using NModbus; +using NModbus; using System.Net.Sockets; namespace TestApp { internal class Program { - private static IMqttClient _MqttClient; - private static Dictionary _CurrentValues = new Dictionary(); + private static EnergyManager _EnergyManager; + static async Task Main(string[] args) { - await ConnectMQTT(); + _EnergyManager = await EnergyManager.Create(); while (true) { @@ -39,7 +37,7 @@ namespace TestApp { try { - var currentWirkleistung = _CurrentValues.GetValueOrDefault(1099528667391UL) / 1000; + var currentWirkleistung = _EnergyManager.ActivePowerPositive; ushort input = master.ReadHoldingRegisters(1, 1000, 1)[0]; ushort output = (ushort)(input + currentWirkleistung); @@ -53,57 +51,5 @@ namespace TestApp } } } - - private static async Task ConnectMQTT() { - var factory = new MqttFactory(); - - _MqttClient = factory.CreateMqttClient(); - - var clientOptions = new MqttClientOptionsBuilder() - .WithTcpServer("localhost") - .Build(); - - Console.WriteLine("Connecting to local MQTT ..."); - await _MqttClient.ConnectAsync(clientOptions); - Console.WriteLine("Connected to local MQTT!"); - - _MqttClient.ApplicationMessageReceivedAsync += Client_ApplicationMessageReceivedAsync; - - var subscribeOptions = factory.CreateSubscribeOptionsBuilder() - .WithTopicFilter( - f => { - f.WithTopic("gdr/local/values/smart-meter"); - } - ) - .Build(); - - Console.WriteLine("Subscribing to smart-meter values ..."); - var response = await _MqttClient.SubscribeAsync(subscribeOptions); - Console.WriteLine("Subscribed to smart-meter values!"); - } - - private static Task Client_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg) - { - switch (arg.ApplicationMessage.Topic) { - case "gdr/local/values/smart-meter": - ParseGDRs(arg.ApplicationMessage.Payload); - break; - } - - return Task.CompletedTask; - } - - private static void ParseGDRs(byte[] payload) - { - var gdrs = GDRs.Parser.ParseFrom(payload); - - if (!gdrs.GDRs_.TryGetValue("smart-meter", out GDR smartMeterGDR)) { - return; - } - - foreach (var value in smartMeterGDR.Values) { - _CurrentValues[value.Key] = value.Value; - } - } } -} \ No newline at end of file +}