From 9e9dc169dd50308570eb3bfcebb59cfb2b1af7ce Mon Sep 17 00:00:00 2001 From: Noe Date: Tue, 4 Jun 2024 12:20:28 +0200 Subject: [PATCH 1/7] Fixed bug with hour-representation in configuration tab (front end) --- csharp/App/SaliMax/deploy.sh | 4 ++-- csharp/App/SaliMax/src/Program.cs | 2 +- .../content/dashboards/Configuration/Configuration.tsx | 8 ++++---- .../src/content/dashboards/Overview/chartOptions.tsx | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/csharp/App/SaliMax/deploy.sh b/csharp/App/SaliMax/deploy.sh index 9bd0d801b..057e274b5 100755 --- a/csharp/App/SaliMax/deploy.sh +++ b/csharp/App/SaliMax/deploy.sh @@ -21,6 +21,6 @@ rsync -v \ ./bin/Release/$dotnet_version/linux-x64/publish/* \ $username@"$salimax_ip":~/salimax -#echo -e "\n============================ Execute ============================\n" +echo -e "\n============================ Execute ============================\n" -#sshpass -p "$root_password" ssh -o StrictHostKeyChecking=no -t "$username"@"$salimax_ip" "echo '$root_password' | sudo -S sh -c 'cd salimax && ./restart'" 2>/dev/null +sshpass -p "$root_password" ssh -o StrictHostKeyChecking=no -t "$username"@"$salimax_ip" "echo '$root_password' | sudo -S sh -c 'cd salimax && ./restart'" 2>/dev/null diff --git a/csharp/App/SaliMax/src/Program.cs b/csharp/App/SaliMax/src/Program.cs index c51db600d..ee0a76355 100644 --- a/csharp/App/SaliMax/src/Program.cs +++ b/csharp/App/SaliMax/src/Program.cs @@ -1,4 +1,4 @@ -#define Amax +#undef Amax #undef GridLimit using System.IO.Compression; diff --git a/typescript/frontend-marios2/src/content/dashboards/Configuration/Configuration.tsx b/typescript/frontend-marios2/src/content/dashboards/Configuration/Configuration.tsx index e1eec0584..66b682adf 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Configuration/Configuration.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Configuration/Configuration.tsx @@ -162,10 +162,10 @@ function Configuration(props: ConfigurationProps) { const handleConfirm = (newDate) => { //console.log('non adapted day is ', newDate); //console.log('adapted day is ', dayjs.utc(newDate).toDate()); - // setFormValues({ - // ...formValues, - // ['calibrationChargeDate']: dayjs(newDate).toDate() - // }); + setFormValues({ + ...formValues, + ['calibrationChargeDate']: dayjs(newDate).toDate() + }); }; const handleSelectedCalibrationChargeDay = (event) => { diff --git a/typescript/frontend-marios2/src/content/dashboards/Overview/chartOptions.tsx b/typescript/frontend-marios2/src/content/dashboards/Overview/chartOptions.tsx index b51e29278..956a343e8 100644 --- a/typescript/frontend-marios2/src/content/dashboards/Overview/chartOptions.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/Overview/chartOptions.tsx @@ -167,7 +167,7 @@ export const getChartOptions = ( style: { fontSize: '12px' }, - offsetY: -185, + offsetY: -190, offsetX: 25, rotate: 0 }, From 382043b79ce41d0b3a3954fa6591ccefd4b164c6 Mon Sep 17 00:00:00 2001 From: atef Date: Tue, 4 Jun 2024 12:23:19 +0200 Subject: [PATCH 2/7] Addf schnieder meter library and app --- .../IEM3kGridMeterDriver.csproj | 16 ++ csharp/App/SchniederMeterDriver/Nic.cs | 149 ++++++++++++++++++ csharp/App/SchniederMeterDriver/Program.cs | 60 +++++++ .../SchniederMeterDriver.cs | 66 ++++++++ .../SchniederMeterDriver.csproj | 26 +++ csharp/App/SchniederMeterDriver/Signal.cs | 16 ++ csharp/App/SchniederMeterDriver/Utils.cs | 49 ++++++ .../App/SchniederMeterDriver/service/log/run | 3 + csharp/App/SchniederMeterDriver/service/run | 3 + csharp/InnovEnergy.sln | 21 +++ .../IEM3kGridMeter/IEM3kGridMeterDevice.cs | 6 +- .../IEM3kGridMeter/IEM3kGridMeterRegisters.cs | 32 ++-- 12 files changed, 430 insertions(+), 17 deletions(-) create mode 100644 csharp/App/IEM3kGridMeterDriver/IEM3kGridMeterDriver.csproj create mode 100644 csharp/App/SchniederMeterDriver/Nic.cs create mode 100644 csharp/App/SchniederMeterDriver/Program.cs create mode 100644 csharp/App/SchniederMeterDriver/SchniederMeterDriver.cs create mode 100644 csharp/App/SchniederMeterDriver/SchniederMeterDriver.csproj create mode 100644 csharp/App/SchniederMeterDriver/Signal.cs create mode 100644 csharp/App/SchniederMeterDriver/Utils.cs create mode 100755 csharp/App/SchniederMeterDriver/service/log/run create mode 100755 csharp/App/SchniederMeterDriver/service/run diff --git a/csharp/App/IEM3kGridMeterDriver/IEM3kGridMeterDriver.csproj b/csharp/App/IEM3kGridMeterDriver/IEM3kGridMeterDriver.csproj new file mode 100644 index 000000000..0ef62c506 --- /dev/null +++ b/csharp/App/IEM3kGridMeterDriver/IEM3kGridMeterDriver.csproj @@ -0,0 +1,16 @@ + + + + + InnovEnergy.Lib.Devices.IEM3kGridMeter + Exe + enable + + + + + + + + + diff --git a/csharp/App/SchniederMeterDriver/Nic.cs b/csharp/App/SchniederMeterDriver/Nic.cs new file mode 100644 index 000000000..8e36c59be --- /dev/null +++ b/csharp/App/SchniederMeterDriver/Nic.cs @@ -0,0 +1,149 @@ +using System.Text.Json.Nodes; +using CliWrap; +using CliWrap.Buffered; + +namespace InnovEnergy.App.SchniederDriver; + +public readonly struct Nic +{ + private static Command IpCommand { get; } = Cli + .Wrap("/sbin/ip") + .WithValidation(CommandResultValidation.None); + + private readonly JsonNode _Node; + + private Nic(JsonNode node) + { + _Node = node; + } + + public Boolean IsEthernet + { + get + { + try + { + return _Node["link_type"]!.GetValue() == "ether"; + } + catch + { + return false; + } + } + } + + public Boolean IsUp + { + get + { + // ReSharper disable once StringLiteralTypo + try + { + return _Node["operstate"]!.GetValue() == "UP"; + } + catch + { + return false; + } + } + } + + public IReadOnlyList Ip4Addresses + { + get + { + // ReSharper disable once StringLiteralTypo + try + { + return _Node["addr_info"]! + .AsArray() + .TryWhere(n => n!["family"]!.GetValue() == "inet") + .TrySelect(n => n!["local"]!.GetValue()) + .ToList(); + } + catch + { + return Array.Empty(); + } + } + } + + public String Name + { + get + { + // ReSharper disable once StringLiteralTypo + try + { + return _Node["ifname"]!.GetValue(); + } + catch + { + return ""; + } + } + } + + + + public async Task AddPointToPoint(String sourceAddress, String destinationAddress) + { + var result = await IpCommand + .WithArguments($"address add local {sourceAddress} peer {destinationAddress} dev {Name}") + .ExecuteAsync(); + + return result.ExitCode == 0; + } + + public async Task RemoveAddress(String address) + { + var result = await IpCommand + .WithArguments($"address del {address} dev {Name}") + .ExecuteBufferedAsync(); + + return result.ExitCode == 0; + } + + + public async Task AddRoute(String route) + { + var result = await IpCommand + .WithArguments($"route add {route} dev {Name}") + .ExecuteAsync(); + + return result.ExitCode == 0; + } + + public async Task RemoveRoute(String route) + { + var result = await IpCommand + .WithArguments($"route del {route} dev {Name}") + .ExecuteAsync(); + + return result.ExitCode == 0; + } + + + public static async Task> GetNetworkInterfaces() + { + + try + { + var result = await IpCommand + .WithArguments("-details -pretty -json address") + .ExecuteBufferedAsync(); + + return JsonNode + .Parse(result.StandardOutput)! + .AsArray() + .Where(n => n != null) + .Select(n => new Nic(n!)) + .ToList(); + } + catch + { + return Array.Empty(); + } + } + +} \ No newline at end of file diff --git a/csharp/App/SchniederMeterDriver/Program.cs b/csharp/App/SchniederMeterDriver/Program.cs new file mode 100644 index 000000000..d7a975cc1 --- /dev/null +++ b/csharp/App/SchniederMeterDriver/Program.cs @@ -0,0 +1,60 @@ +using InnovEnergy.App.SchniederDriver; +using InnovEnergy.Lib.Protocols.DBus; +using InnovEnergy.Lib.Utils; +using InnovEnergy.Lib.Utils.Net; + + +// dotnet publish EmuMeter.csproj -c Release -r linux-arm -p:PublishSingleFile=true --self-contained true && \ +// rsync -av bin/Release/net6.0/linux-arm/publish/ root@10.2.1.6:/home/root/emu && clear && \ +// ssh root@10.2.1.6 /home/root/emu/EmuMeter + + +Console.WriteLine("Starting Schnieder Driver " + Config.Version); + +var networkInterfaces = await Nic.GetNetworkInterfaces(); + +var candidates = networkInterfaces.Where(n => n.IsUp && + n.IsEthernet && + (!n.Ip4Addresses.Any() || n.Ip4Addresses.Contains(Config.OwnAddress))); + +foreach (var nic in candidates) +{ + Console.WriteLine($"Found new network interface: {nic.Name}"); + + if (!nic.Ip4Addresses.Contains(Config.OwnAddress)) + { + Console.WriteLine($"Configuring Point-to-Point connection on {nic.Name}"); + Console.WriteLine($" own address: {Config.OwnAddress}"); + Console.WriteLine($" peer address: {Config.PeerAddress}"); + + var success = await nic.AddPointToPoint($"{Config.OwnAddress}/16", $"{Config.PeerAddress}/16"); + + if (!success) + { + Console.WriteLine($"Failed to configure network interface: {nic.Name}"); + continue; + } + } + + Console.WriteLine($"Pinging peer @ {Config.PeerAddress}"); + + var ping = await Config.PeerAddress.Ping(); + + if (ping) + { + Console.WriteLine($"Got answer from {Config.PeerAddress}"); + var ex = await SchniederMeterDriver.Run($"{Config.PeerAddress}:{Config.PeerPort}", Bus.System); + + Console.WriteLine($"{nameof(SchniederMeterDriver)} FAILED with\n{ex}"); + } + else + { + Console.WriteLine($"No answer from {Config.PeerAddress}"); + } + + Console.Write($"Removing Point-to-Point connection on {nic.Name} ..."); + var removed = await nic.RemoveAddress($"{Config.OwnAddress}/16"); + Console.WriteLine(removed ? "done" : "failed"); +} + +Console.WriteLine("Stopping EmuMeter Driver"); \ No newline at end of file diff --git a/csharp/App/SchniederMeterDriver/SchniederMeterDriver.cs b/csharp/App/SchniederMeterDriver/SchniederMeterDriver.cs new file mode 100644 index 000000000..786be532c --- /dev/null +++ b/csharp/App/SchniederMeterDriver/SchniederMeterDriver.cs @@ -0,0 +1,66 @@ +using System.Reactive.Linq; +using InnovEnergy.Lib.Devices.IEM3kGridMeter; +using InnovEnergy.Lib.Protocols.DBus; +using InnovEnergy.Lib.Protocols.Modbus.Clients; +using InnovEnergy.Lib.Utils; +using InnovEnergy.Lib.Victron.VeDBus; + +namespace InnovEnergy.App.SchniederDriver; + +public static class SchniederMeterDriver +{ + public static Task Run(String hostName, Bus dbusAddress) + { + return Run(hostName, ModbusTcpClient.DefaultPort, dbusAddress); + } + + public static async Task Run(String hostName, UInt16 port, Bus dbusAddress) + { + // var ep = new UnixDomainSocketEndPoint("/home/eef/graber_dbus.sock"); + // var auth = AuthenticationMethod.ExternalAsRoot(); + // dbusAddress = new Bus(ep, auth); + + var schnieder = new Iem3KGridMeterDevice(hostName, port, Config.ModbusNodeId); + + + var schniederStatus = Observable + .Interval(Config.UpdatePeriod) + .Select(_ => schnieder.Read()) + .Publish(); + + var poller = schniederStatus.Connect(); + + var properties = Config.DefaultProperties; + + var signals = Config + .Signals + .Select(signal => schniederStatus.Select(signal.ToVeProperty)) + .Merge() + .Do(p => properties.Set(p)); + + // TODO: remove when possible + // Apparently some VE services need to be periodically reminded that + // this service is /Connected + schniederStatus.Subscribe(_ => properties.Set("/Connected", 1)); + + // Wait until status is read once to make sure all + // properties are set when we go onto the bus. + var dbus = schniederStatus + .Skip(1) + .Take(1) + .SelectMany(_ => PublishPropertiesOnDBus(properties, dbusAddress)); + + return await signals + .MergeErrors(dbus) + .Finally(poller.Dispose) + .SelectErrors(); + + } + + + private static Task PublishPropertiesOnDBus(VeProperties properties, Bus bus) + { + Console.WriteLine($"Connecting to DBus {bus}"); + return properties.PublishOnDBus(bus, Config.BusName); + } +} \ No newline at end of file diff --git a/csharp/App/SchniederMeterDriver/SchniederMeterDriver.csproj b/csharp/App/SchniederMeterDriver/SchniederMeterDriver.csproj new file mode 100644 index 000000000..ea039329c --- /dev/null +++ b/csharp/App/SchniederMeterDriver/SchniederMeterDriver.csproj @@ -0,0 +1,26 @@ + + + + + InnovEnergy.App.SchniederDriver + SchniederDriver + + + + + + + + + + + + + + + + + + + + diff --git a/csharp/App/SchniederMeterDriver/Signal.cs b/csharp/App/SchniederMeterDriver/Signal.cs new file mode 100644 index 000000000..6cda4d3dd --- /dev/null +++ b/csharp/App/SchniederMeterDriver/Signal.cs @@ -0,0 +1,16 @@ +using InnovEnergy.Lib.Devices.EmuMeter; +using InnovEnergy.Lib.Protocols.DBus.Protocol.DataTypes; +using InnovEnergy.Lib.Victron.VeDBus; + +namespace InnovEnergy.App.SchniederDriver; + + +// TODO: Does not compile +public record Signal(Func Source, ObjectPath Path, String Format = "") +{ + public VeProperty ToVeProperty(EmuMeterStatus status) + { + var value = Source(status); + return new VeProperty(Path, value, String.Format($"{{0:{Format}}}", value)); + } +} \ No newline at end of file diff --git a/csharp/App/SchniederMeterDriver/Utils.cs b/csharp/App/SchniederMeterDriver/Utils.cs new file mode 100644 index 000000000..53d5ca9d5 --- /dev/null +++ b/csharp/App/SchniederMeterDriver/Utils.cs @@ -0,0 +1,49 @@ +namespace InnovEnergy.App.SchniederDriver; + +public static class Utils +{ + public static IEnumerable TryWhere(this IEnumerable src, Func predicate) + { + foreach (var e in src) + { + var ok = false; + + try + { + ok = predicate(e); + } + catch + { + // ignored + } + + if (ok) + yield return e; + } + } + + public static IEnumerable TrySelect(this IEnumerable src, Func map) + { + foreach (var e in src) + { + var ok = false; + var result = default(R); + + try + { + result = map(e); + ok = true; + } + catch + { + // ignored + } + + if (ok) + yield return result!; + } + } + + + +} \ No newline at end of file diff --git a/csharp/App/SchniederMeterDriver/service/log/run b/csharp/App/SchniederMeterDriver/service/log/run new file mode 100755 index 000000000..62e2f8679 --- /dev/null +++ b/csharp/App/SchniederMeterDriver/service/log/run @@ -0,0 +1,3 @@ +#!/bin/sh +exec 2>&1 +exec multilog t s25000 n4 /var/log/EmuMeter diff --git a/csharp/App/SchniederMeterDriver/service/run b/csharp/App/SchniederMeterDriver/service/run new file mode 100755 index 000000000..58cdb6ff7 --- /dev/null +++ b/csharp/App/SchniederMeterDriver/service/run @@ -0,0 +1,3 @@ +#!/bin/sh +exec 2>&1 +exec softlimit -d 100000000 -s 1000000 -a 100000000 /opt/innovenergy/EmuMeter/EmuMeter diff --git a/csharp/InnovEnergy.sln b/csharp/InnovEnergy.sln index 624ace482..60951da25 100644 --- a/csharp/InnovEnergy.sln +++ b/csharp/InnovEnergy.sln @@ -87,6 +87,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Doepke", "Lib\Devices\Doepk EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amax5070", "Lib\Devices\Amax5070\Amax5070.csproj", "{09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sofar", "App\Sofar\Sofar.csproj", "{6B98449D-BF75-415A-8893-E49518F9307D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SofarInverter", "Lib\Devices\SofarInverter\SofarInverter.csproj", "{2C7F3D89-402B-43CB-988E-8D2D853BEF44}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SchniederMeterDriver", "App\SchniederMeterDriver\SchniederMeterDriver.csproj", "{2E7E7657-3A53-4B62-8927-FE9A082B81DE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -226,6 +232,18 @@ Global {09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}.Debug|Any CPU.Build.0 = Debug|Any CPU {09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}.Release|Any CPU.ActiveCfg = Release|Any CPU {09E280B0-43D3-47BD-AF15-CF4FCDD24FE6}.Release|Any CPU.Build.0 = Release|Any CPU + {6B98449D-BF75-415A-8893-E49518F9307D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B98449D-BF75-415A-8893-E49518F9307D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B98449D-BF75-415A-8893-E49518F9307D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B98449D-BF75-415A-8893-E49518F9307D}.Release|Any CPU.Build.0 = Release|Any CPU + {2C7F3D89-402B-43CB-988E-8D2D853BEF44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2C7F3D89-402B-43CB-988E-8D2D853BEF44}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2C7F3D89-402B-43CB-988E-8D2D853BEF44}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2C7F3D89-402B-43CB-988E-8D2D853BEF44}.Release|Any CPU.Build.0 = Release|Any CPU + {2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2E7E7657-3A53-4B62-8927-FE9A082B81DE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {CF4834CB-91B7-4172-AC13-ECDA8613CD17} = {145597B4-3E30-45E6-9F72-4DD43194539A} @@ -265,5 +283,8 @@ Global {73B97F6E-2BDC-40DA-84A7-7FB0264387D6} = {AD5B98A8-AB7F-4DA2-B66D-5B4E63E7D854} {C2B14CD4-1BCA-4933-96D9-92F40EACD2B9} = {4931A385-24DC-4E78-BFF4-356F8D6D5183} {09E280B0-43D3-47BD-AF15-CF4FCDD24FE6} = {4931A385-24DC-4E78-BFF4-356F8D6D5183} + {6B98449D-BF75-415A-8893-E49518F9307D} = {145597B4-3E30-45E6-9F72-4DD43194539A} + {2C7F3D89-402B-43CB-988E-8D2D853BEF44} = {4931A385-24DC-4E78-BFF4-356F8D6D5183} + {2E7E7657-3A53-4B62-8927-FE9A082B81DE} = {145597B4-3E30-45E6-9F72-4DD43194539A} EndGlobalSection EndGlobal diff --git a/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterDevice.cs b/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterDevice.cs index de9e04b62..38dfecda4 100644 --- a/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterDevice.cs +++ b/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterDevice.cs @@ -10,8 +10,8 @@ public class Iem3KGridMeterDevice: ModbusDevice public Iem3KGridMeterDevice(String hostname, UInt16 port = 502, Byte slaveId = 1) : this(new TcpChannel(hostname, port), slaveId) { } - - public Iem3KGridMeterDevice(Channel channel, Byte slaveId = 1) : base(new ModbusTcpClient(channel, slaveId)) + + private Iem3KGridMeterDevice(Channel channel, Byte slaveId = 1) : base(new ModbusTcpClient(channel, slaveId)) { } @@ -47,4 +47,6 @@ public class Iem3KGridMeterDevice: ModbusDevice $"Failed to write data to {nameof(Iem3KGridMeterDevice)}".WriteLine(); } } + + } \ No newline at end of file diff --git a/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterRegisters.cs b/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterRegisters.cs index d7db41717..fb0183b76 100644 --- a/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterRegisters.cs +++ b/csharp/Lib/Devices/IEM3kGridMeter/IEM3kGridMeterRegisters.cs @@ -12,25 +12,25 @@ using Float32 = Single; [AddressOffset(-2)] // why? -public class Iem3KGridMeterRegisters : IAc3Meter +public class Iem3KGridMeterRegisters //: IAc3Meter { private const Float32 ZeroBecauseReactivePowerNotSupported = 0; // TODO - [HoldingRegister(3054)] private Float32 _ActivePowerL1; - [HoldingRegister(3056)] private Float32 _ActivePowerL2; - [HoldingRegister(3058)] private Float32 _ActivePowerL3; + [HoldingRegister(3054)] public Float32 ActivePowerL1; + [HoldingRegister(3056)] public Float32 ActivePowerL2; + [HoldingRegister(3058)] public Float32 ActivePowerL3; - [HoldingRegister(3000)] private Float32 _CurrentL1; - [HoldingRegister(3002)] private Float32 _CurrentL2; - [HoldingRegister(3004)] private Float32 _CurrentL3; - - [HoldingRegister(3028)] private Float32 _VoltageL1N; - [HoldingRegister(3030)] private Float32 _VoltageL2N; - [HoldingRegister(3032)] private Float32 _VoltageL3N; - - [HoldingRegister(3110)] private Float32 _Frequency; + //[HoldingRegister(3000)] private Float32 _CurrentL1; + //[HoldingRegister(3002)] private Float32 _CurrentL2; + //[HoldingRegister(3004)] private Float32 _CurrentL3; + // + //[HoldingRegister(3028)] private Float32 _VoltageL1N; + //[HoldingRegister(3030)] private Float32 _VoltageL2N; + //[HoldingRegister(3032)] private Float32 _VoltageL3N; + // + //[HoldingRegister(3110)] private Float32 _Frequency; //[HoldingRegister(9012)] private Float32 _ReactivePowerL1; //[HoldingRegister(9014)] private Float32 _ReactivePowerL2; @@ -45,7 +45,7 @@ public class Iem3KGridMeterRegisters : IAc3Meter //[HoldingRegister(9026)] private Float32 _ApparentPowerL3; - public Ac3Bus Ac => new Ac3Bus + /*public Ac3Bus Ac => new Ac3Bus { L1 = new () { @@ -66,7 +66,9 @@ public class Iem3KGridMeterRegisters : IAc3Meter Phi = Atan2(ZeroBecauseReactivePowerNotSupported, _ActivePowerL3) }, Frequency = _Frequency - }; + };*/ + + } From 2c6ab05fbe3f5985c91895ba5091f978588ee3c8 Mon Sep 17 00:00:00 2001 From: atef Date: Tue, 4 Jun 2024 12:25:51 +0200 Subject: [PATCH 3/7] add config file to schnieder app --- csharp/App/SchniederMeterDriver/Config.cs | 65 +++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 csharp/App/SchniederMeterDriver/Config.cs diff --git a/csharp/App/SchniederMeterDriver/Config.cs b/csharp/App/SchniederMeterDriver/Config.cs new file mode 100644 index 000000000..415808049 --- /dev/null +++ b/csharp/App/SchniederMeterDriver/Config.cs @@ -0,0 +1,65 @@ +using System.Reflection; +using InnovEnergy.Lib.Victron.VeDBus; + +namespace InnovEnergy.App.SchniederDriver; + +public static class Config +{ + public const String Version = "1.0"; + public const String BusName = "com.victronenergy.grid.Schnieder"; + public const Byte ModbusNodeId = 1; + public const String OwnAddress = "10.0.0.1"; + public const String PeerAddress = "10.0.0.2"; + //public const String PeerAddress = "127.0.0.1"; + public const UInt16 PeerPort = 502; + + public static TimeSpan TcpTimeout { get; } = TimeSpan.FromSeconds(2); + + + public static readonly TimeSpan UpdatePeriod = TimeSpan.FromSeconds(1); + + public static readonly IReadOnlyList Signals = new Signal[] + { + new(s => s.Ac.L1.Current, "/Ac/L1/Current", "0.0 A"), + new(s => s.Ac.L2.Current, "/Ac/L2/Current", "0.0 A"), + new(s => s.Ac.L3.Current, "/Ac/L3/Current", "0.0 A"), + new(s => s.Ac.L1.Current + s.Ac.L2.Current + s.Ac.L3.Current, "/Ac/Current", "0.0 A"), + + new(s => s.Ac.L1.Voltage, "/Ac/L1/Voltage", "0.0 A"), + new(s => s.Ac.L2.Voltage, "/Ac/L2/Voltage", "0.0 A"), + new(s => s.Ac.L3.Voltage, "/Ac/L3/Voltage", "0.0 A"), + new(s => (s.Ac.L1.Voltage + s.Ac.L2.Voltage + s.Ac.L3.Voltage) / 3.0m, "/Ac/Voltage", "0.0 A"), + + new(s => s.Ac.L1.ActivePower, "/Ac/L1/Power", "0 W"), + new(s => s.Ac.L2.ActivePower, "/Ac/L2/Power", "0 W"), + new(s => s.Ac.L3.ActivePower, "/Ac/L3/Power", "0 W"), + new(s => s.Ac.ActivePower, "/Ac/Power", "0 W"), + + // new(s => s.EnergyImportL123, "Ac/Energy/Forward", "0.00 kWh"), + // new(s => s.EnergyExportL123, "Ac/Energy/Reverse", "0.00 kWh"), + // + // new(s => s.EnergyImportL1, "Ac/L1/Energy/Forward", "0.00 kWh"), + // new(s => s.EnergyExportL1, "Ac/L1/Energy/Reverse", "0.00 kWh"), + // + // new(s => s.EnergyImportL2, "Ac/L2/Energy/Forward", "0.00 kWh"), + // new(s => s.EnergyExportL2, "Ac/L2/Energy/Reverse", "0.00 kWh"), + // + // new(s => s.EnergyImportL3, "Ac/L3/Energy/Forward", "0.00 kWh"), + // new(s => s.EnergyExportL3, "Ac/L3/Energy/Reverse", "0.00 kWh"), + }; + + public static VeProperties DefaultProperties => new VeProperties + { + new("/ProductName" , "Grid meter" ), + new("/CustomName" , "EMU Professional II"), + new("/DeviceInstance" , 30), + new("/DeviceType" , 72), + new("/Mgmt/Connection" , "Modbus TCP"), + new("/Mgmt/ProcessName" , Assembly.GetEntryAssembly()?.Location ?? "unknown"), + new("/Mgmt/ProcessVersion", Version), + new("/Connected" , 1), + new("/ProductId" , 45058, "b002"), + new("/Role" , "grid"), + }; + +} \ No newline at end of file From 6383bd7f4c3910afc99e1e5e8660946fa316b3aa Mon Sep 17 00:00:00 2001 From: kostas Date: Tue, 4 Jun 2024 14:57:35 +0200 Subject: [PATCH 4/7] Temporary cahnges to remove errors I also need to adjust Signal --- .../IEM3kGridMeterDriver.csproj | 16 ---------------- csharp/App/SchniederMeterDriver/Signal.cs | 5 +++-- 2 files changed, 3 insertions(+), 18 deletions(-) delete mode 100644 csharp/App/IEM3kGridMeterDriver/IEM3kGridMeterDriver.csproj diff --git a/csharp/App/IEM3kGridMeterDriver/IEM3kGridMeterDriver.csproj b/csharp/App/IEM3kGridMeterDriver/IEM3kGridMeterDriver.csproj deleted file mode 100644 index 0ef62c506..000000000 --- a/csharp/App/IEM3kGridMeterDriver/IEM3kGridMeterDriver.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - - InnovEnergy.Lib.Devices.IEM3kGridMeter - Exe - enable - - - - - - - - - diff --git a/csharp/App/SchniederMeterDriver/Signal.cs b/csharp/App/SchniederMeterDriver/Signal.cs index 6cda4d3dd..a8415d94e 100644 --- a/csharp/App/SchniederMeterDriver/Signal.cs +++ b/csharp/App/SchniederMeterDriver/Signal.cs @@ -1,4 +1,5 @@ using InnovEnergy.Lib.Devices.EmuMeter; +using InnovEnergy.Lib.Devices.IEM3kGridMeter; using InnovEnergy.Lib.Protocols.DBus.Protocol.DataTypes; using InnovEnergy.Lib.Victron.VeDBus; @@ -6,9 +7,9 @@ namespace InnovEnergy.App.SchniederDriver; // TODO: Does not compile -public record Signal(Func Source, ObjectPath Path, String Format = "") +public record Signal(Func Source, ObjectPath Path, String Format = "") { - public VeProperty ToVeProperty(EmuMeterStatus status) + public VeProperty ToVeProperty(Iem3KGridMeterRegisters status) { var value = Source(status); return new VeProperty(Path, value, String.Format($"{{0:{Format}}}", value)); From 1f3d4c74b99fa2398c1633905d5d430550947c54 Mon Sep 17 00:00:00 2001 From: atef Date: Tue, 4 Jun 2024 15:28:17 +0200 Subject: [PATCH 5/7] Update SchneiderMeterDriver --- .../Config.cs | 28 +++++++++---------- .../Program.cs | 10 +++---- .../SchneiderMeterDriver.cs} | 4 +-- .../SchneiderMeterDriver.csproj} | 2 +- .../Signal.cs | 3 +- csharp/App/SchneiderMeterDriver/debug.sh | 20 +++++++++++++ csharp/InnovEnergy.sln | 2 +- 7 files changed, 44 insertions(+), 25 deletions(-) rename csharp/App/{SchniederMeterDriver => SchneiderMeterDriver}/Config.cs (66%) rename csharp/App/{SchniederMeterDriver => SchneiderMeterDriver}/Program.cs (86%) rename csharp/App/{SchniederMeterDriver/SchniederMeterDriver.cs => SchneiderMeterDriver/SchneiderMeterDriver.cs} (96%) rename csharp/App/{SchniederMeterDriver/SchniederMeterDriver.csproj => SchneiderMeterDriver/SchneiderMeterDriver.csproj} (92%) rename csharp/App/{SchniederMeterDriver => SchneiderMeterDriver}/Signal.cs (85%) create mode 100755 csharp/App/SchneiderMeterDriver/debug.sh diff --git a/csharp/App/SchniederMeterDriver/Config.cs b/csharp/App/SchneiderMeterDriver/Config.cs similarity index 66% rename from csharp/App/SchniederMeterDriver/Config.cs rename to csharp/App/SchneiderMeterDriver/Config.cs index 415808049..c7dd3ccde 100644 --- a/csharp/App/SchniederMeterDriver/Config.cs +++ b/csharp/App/SchneiderMeterDriver/Config.cs @@ -1,7 +1,7 @@ using System.Reflection; using InnovEnergy.Lib.Victron.VeDBus; -namespace InnovEnergy.App.SchniederDriver; +namespace InnovEnergy.App.SchneiderDriver; public static class Config { @@ -20,20 +20,20 @@ public static class Config public static readonly IReadOnlyList Signals = new Signal[] { - new(s => s.Ac.L1.Current, "/Ac/L1/Current", "0.0 A"), - new(s => s.Ac.L2.Current, "/Ac/L2/Current", "0.0 A"), - new(s => s.Ac.L3.Current, "/Ac/L3/Current", "0.0 A"), - new(s => s.Ac.L1.Current + s.Ac.L2.Current + s.Ac.L3.Current, "/Ac/Current", "0.0 A"), + // new(s => s..CurrentL1, "/Ac/L1/Current", "0.0 A"), + // new(s => s..CurrentL2, "/Ac/L2/Current", "0.0 A"), + // new(s => s..CurrentL3, "/Ac/L3/Current", "0.0 A"), + // new(s => s..CurrentL1 + s.Ac.L2.Current + s.Ac.L3.Current, "/Ac/Current", "0.0 A"), - new(s => s.Ac.L1.Voltage, "/Ac/L1/Voltage", "0.0 A"), - new(s => s.Ac.L2.Voltage, "/Ac/L2/Voltage", "0.0 A"), - new(s => s.Ac.L3.Voltage, "/Ac/L3/Voltage", "0.0 A"), - new(s => (s.Ac.L1.Voltage + s.Ac.L2.Voltage + s.Ac.L3.Voltage) / 3.0m, "/Ac/Voltage", "0.0 A"), + // new(s => s.Ac.L1.Voltage, "/Ac/L1/Voltage", "0.0 A"), + // new(s => s.Ac.L2.Voltage, "/Ac/L2/Voltage", "0.0 A"), + // new(s => s.Ac.L3.Voltage, "/Ac/L3/Voltage", "0.0 A"), + // new(s => (s.Ac.L1.Voltage + s.Ac.L2.Voltage + s.Ac.L3.Voltage) / 3.0m, "/Ac/Voltage", "0.0 A"), - new(s => s.Ac.L1.ActivePower, "/Ac/L1/Power", "0 W"), - new(s => s.Ac.L2.ActivePower, "/Ac/L2/Power", "0 W"), - new(s => s.Ac.L3.ActivePower, "/Ac/L3/Power", "0 W"), - new(s => s.Ac.ActivePower, "/Ac/Power", "0 W"), + new(s => s.ActivePowerL1, "/Ac/L1/Power", "0 W"), + new(s => s.ActivePowerL2, "/Ac/L2/Power", "0 W"), + new(s => s.ActivePowerL3, "/Ac/L3/Power", "0 W"), + new(s => (s.ActivePowerL1 + s.ActivePowerL2 + s.ActivePowerL3), "/Ac/Power", "0 W"), // new(s => s.EnergyImportL123, "Ac/Energy/Forward", "0.00 kWh"), // new(s => s.EnergyExportL123, "Ac/Energy/Reverse", "0.00 kWh"), @@ -51,7 +51,7 @@ public static class Config public static VeProperties DefaultProperties => new VeProperties { new("/ProductName" , "Grid meter" ), - new("/CustomName" , "EMU Professional II"), + new("/CustomName" , "Schneider Professional II"), new("/DeviceInstance" , 30), new("/DeviceType" , 72), new("/Mgmt/Connection" , "Modbus TCP"), diff --git a/csharp/App/SchniederMeterDriver/Program.cs b/csharp/App/SchneiderMeterDriver/Program.cs similarity index 86% rename from csharp/App/SchniederMeterDriver/Program.cs rename to csharp/App/SchneiderMeterDriver/Program.cs index d7a975cc1..54bc7c2b8 100644 --- a/csharp/App/SchniederMeterDriver/Program.cs +++ b/csharp/App/SchneiderMeterDriver/Program.cs @@ -1,4 +1,4 @@ -using InnovEnergy.App.SchniederDriver; +using InnovEnergy.App.SchneiderDriver; using InnovEnergy.Lib.Protocols.DBus; using InnovEnergy.Lib.Utils; using InnovEnergy.Lib.Utils.Net; @@ -9,7 +9,7 @@ using InnovEnergy.Lib.Utils.Net; // ssh root@10.2.1.6 /home/root/emu/EmuMeter -Console.WriteLine("Starting Schnieder Driver " + Config.Version); +Console.WriteLine("Starting Schneider Driver " + Config.Version); var networkInterfaces = await Nic.GetNetworkInterfaces(); @@ -43,9 +43,9 @@ foreach (var nic in candidates) if (ping) { Console.WriteLine($"Got answer from {Config.PeerAddress}"); - var ex = await SchniederMeterDriver.Run($"{Config.PeerAddress}:{Config.PeerPort}", Bus.System); + var ex = await SchneiderMeterDriver.Run($"{Config.PeerAddress}:{Config.PeerPort}", Bus.System); - Console.WriteLine($"{nameof(SchniederMeterDriver)} FAILED with\n{ex}"); + Console.WriteLine($"{nameof(SchneiderMeterDriver)} FAILED with\n{ex}"); } else { @@ -57,4 +57,4 @@ foreach (var nic in candidates) Console.WriteLine(removed ? "done" : "failed"); } -Console.WriteLine("Stopping EmuMeter Driver"); \ No newline at end of file +Console.WriteLine("Stopping SchneiderMeter Driver"); \ No newline at end of file diff --git a/csharp/App/SchniederMeterDriver/SchniederMeterDriver.cs b/csharp/App/SchneiderMeterDriver/SchneiderMeterDriver.cs similarity index 96% rename from csharp/App/SchniederMeterDriver/SchniederMeterDriver.cs rename to csharp/App/SchneiderMeterDriver/SchneiderMeterDriver.cs index 786be532c..7a9205037 100644 --- a/csharp/App/SchniederMeterDriver/SchniederMeterDriver.cs +++ b/csharp/App/SchneiderMeterDriver/SchneiderMeterDriver.cs @@ -5,9 +5,9 @@ using InnovEnergy.Lib.Protocols.Modbus.Clients; using InnovEnergy.Lib.Utils; using InnovEnergy.Lib.Victron.VeDBus; -namespace InnovEnergy.App.SchniederDriver; +namespace InnovEnergy.App.SchneiderDriver; -public static class SchniederMeterDriver +public static class SchneiderMeterDriver { public static Task Run(String hostName, Bus dbusAddress) { diff --git a/csharp/App/SchniederMeterDriver/SchniederMeterDriver.csproj b/csharp/App/SchneiderMeterDriver/SchneiderMeterDriver.csproj similarity index 92% rename from csharp/App/SchniederMeterDriver/SchniederMeterDriver.csproj rename to csharp/App/SchneiderMeterDriver/SchneiderMeterDriver.csproj index ea039329c..ac5b87bcd 100644 --- a/csharp/App/SchniederMeterDriver/SchniederMeterDriver.csproj +++ b/csharp/App/SchneiderMeterDriver/SchneiderMeterDriver.csproj @@ -2,7 +2,7 @@ - InnovEnergy.App.SchniederDriver + InnovEnergy.App.SchneiderDriver SchniederDriver diff --git a/csharp/App/SchniederMeterDriver/Signal.cs b/csharp/App/SchneiderMeterDriver/Signal.cs similarity index 85% rename from csharp/App/SchniederMeterDriver/Signal.cs rename to csharp/App/SchneiderMeterDriver/Signal.cs index a8415d94e..9f9bb2254 100644 --- a/csharp/App/SchniederMeterDriver/Signal.cs +++ b/csharp/App/SchneiderMeterDriver/Signal.cs @@ -1,9 +1,8 @@ -using InnovEnergy.Lib.Devices.EmuMeter; using InnovEnergy.Lib.Devices.IEM3kGridMeter; using InnovEnergy.Lib.Protocols.DBus.Protocol.DataTypes; using InnovEnergy.Lib.Victron.VeDBus; -namespace InnovEnergy.App.SchniederDriver; +namespace InnovEnergy.App.SchneiderDriver; // TODO: Does not compile diff --git a/csharp/App/SchneiderMeterDriver/debug.sh b/csharp/App/SchneiderMeterDriver/debug.sh new file mode 100755 index 000000000..c138cfdb8 --- /dev/null +++ b/csharp/App/SchneiderMeterDriver/debug.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +csproj="SchneiderMeterDriver.csproj" +exe="SchneiderMeterDriver" +#remote="10.2.1.6" +remote="10.2.4.155" + +netVersion="net6.0" +platform="linux-arm" +config="Release" +host="root@$remote" +dir="/opt/victronenergy/$exe" + +set -e + +dotnet publish "$csproj" -c $config -r $platform -p:SuppressTrimmAnalysisWarnings=true -p:PublishSingleFile=true -p:PublishTrimmed=true -p:DebugType=None -p:DebugSymbols=false --self-contained true +rsync -av "bin/$config/$netVersion/$platform/publish/" "$host:$dir" +#clear +#ssh "$host" "$dir/$exe" + \ No newline at end of file diff --git a/csharp/InnovEnergy.sln b/csharp/InnovEnergy.sln index 60951da25..10c541c54 100644 --- a/csharp/InnovEnergy.sln +++ b/csharp/InnovEnergy.sln @@ -91,7 +91,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sofar", "App\Sofar\Sofar.cs EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SofarInverter", "Lib\Devices\SofarInverter\SofarInverter.csproj", "{2C7F3D89-402B-43CB-988E-8D2D853BEF44}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SchniederMeterDriver", "App\SchniederMeterDriver\SchniederMeterDriver.csproj", "{2E7E7657-3A53-4B62-8927-FE9A082B81DE}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SchneiderMeterDriver", "App\SchneiderMeterDriver\SchneiderMeterDriver.csproj", "{2E7E7657-3A53-4B62-8927-FE9A082B81DE}" EndProject Global From f70e3fe180c02cac229fb255cd318ff4f1f59c91 Mon Sep 17 00:00:00 2001 From: atef Date: Tue, 4 Jun 2024 15:37:25 +0200 Subject: [PATCH 6/7] Update SchneiderMeterDriver nic file --- csharp/App/SaliMax/src/Ess/Controller.cs | 2 +- .../App/{SchniederMeterDriver => SchneiderMeterDriver}/Nic.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename csharp/App/{SchniederMeterDriver => SchneiderMeterDriver}/Nic.cs (98%) diff --git a/csharp/App/SaliMax/src/Ess/Controller.cs b/csharp/App/SaliMax/src/Ess/Controller.cs index 3d35cf2d7..1cc305352 100644 --- a/csharp/App/SaliMax/src/Ess/Controller.cs +++ b/csharp/App/SaliMax/src/Ess/Controller.cs @@ -195,9 +195,9 @@ public static class Controller var mustDoCalibrationCharge = calibrationChargeForced == CalibrationChargeType.ChargePermanently || (calibrationChargeForced == CalibrationChargeType.AdditionallyOnce && additionalCalibrationRequired) || (calibrationChargeForced == CalibrationChargeType.RepetitivelyEvery && repetitiveCalibrationRequired); + Console.WriteLine("Next Repetitive calibration charge date is "+statusRecord.Config.DayAndTimeForRepetitiveCalibration); Console.WriteLine("Next Additional calibration charge date is "+statusRecord.Config.DayAndTimeForAdditionalCalibration); - //Console.WriteLine("Time now is "+DateTime.Now); if (statusRecord.Battery is not null) { diff --git a/csharp/App/SchniederMeterDriver/Nic.cs b/csharp/App/SchneiderMeterDriver/Nic.cs similarity index 98% rename from csharp/App/SchniederMeterDriver/Nic.cs rename to csharp/App/SchneiderMeterDriver/Nic.cs index 8e36c59be..a580f6fd3 100644 --- a/csharp/App/SchniederMeterDriver/Nic.cs +++ b/csharp/App/SchneiderMeterDriver/Nic.cs @@ -2,7 +2,7 @@ using System.Text.Json.Nodes; using CliWrap; using CliWrap.Buffered; -namespace InnovEnergy.App.SchniederDriver; +namespace InnovEnergy.App.SchneiderDriver; public readonly struct Nic { From 493b76e0ed35e2301387bf0a5ba25b36698253ed Mon Sep 17 00:00:00 2001 From: kostas Date: Wed, 5 Jun 2024 09:57:09 +0200 Subject: [PATCH 7/7] fix: trywhere --- csharp/App/SchneiderMeterDriver/Utils.cs | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 csharp/App/SchneiderMeterDriver/Utils.cs diff --git a/csharp/App/SchneiderMeterDriver/Utils.cs b/csharp/App/SchneiderMeterDriver/Utils.cs new file mode 100644 index 000000000..4b5735a35 --- /dev/null +++ b/csharp/App/SchneiderMeterDriver/Utils.cs @@ -0,0 +1,49 @@ +namespace InnovEnergy.App.SchneiderDriver; + +public static class Utils +{ + public static IEnumerable TryWhere(this IEnumerable src, Func predicate) + { + foreach (var e in src) + { + var ok = false; + + try + { + ok = predicate(e); + } + catch + { + // ignored + } + + if (ok) + yield return e; + } + } + + public static IEnumerable TrySelect(this IEnumerable src, Func map) + { + foreach (var e in src) + { + var ok = false; + var result = default(R); + + try + { + result = map(e); + ok = true; + } + catch + { + // ignored + } + + if (ok) + yield return result!; + } + } + + + +} \ No newline at end of file