diff --git a/csharp/App/SaliMax/SaliMax.csproj b/csharp/App/SaliMax/SaliMax.csproj index c647ee0d5..6802aca05 100644 --- a/csharp/App/SaliMax/SaliMax.csproj +++ b/csharp/App/SaliMax/SaliMax.csproj @@ -2,23 +2,23 @@ - - - - - - - - - - + + + + + + + + + + - - - - + + + + diff --git a/csharp/App/SaliMax/src/Controller/AvgBatteriesStatus.cs b/csharp/App/SaliMax/src/Controller/AvgBatteriesStatus.cs index b62316d85..745b18187 100644 --- a/csharp/App/SaliMax/src/Controller/AvgBatteriesStatus.cs +++ b/csharp/App/SaliMax/src/Controller/AvgBatteriesStatus.cs @@ -1,51 +1,53 @@ using InnovEnergy.Lib.Devices.Battery48TL; +using InnovEnergy.Lib.StatusApi; +using InnovEnergy.Lib.Units; +using InnovEnergy.Lib.Units.Composite; +using static InnovEnergy.Lib.Devices.Battery48TL.TemperatureState; namespace InnovEnergy.App.SaliMax.Controller; -public class AvgBatteriesStatus +public static class AvgBatteriesStatus { - public Decimal Soc { get; set; } - public Decimal Current { get; set; } - public Decimal Voltage { get; set; } - public Decimal Power { get; set; } - public Decimal BusVoltage { get; set; } - public Decimal BatteryTemperature { get; set; } - public IReadOnlyList Warnings { get; set; } - public IReadOnlyList Alarms { get; set; } - public Boolean HeaterOn { get; set; } - public Boolean EocReached { get; set; } - public Boolean BatteryCold { get; set; } - public Decimal MaxChargingPower { get; set; } - public Decimal MaxDischargingPower { get; set; } - - public static AvgBatteriesStatus ReadBatteriesStatus(IReadOnlyList batteriesStatus) + public static CombinedStatus? Combine(this IReadOnlyList stati) { - var soc = batteriesStatus.Any() ? batteriesStatus.Average(b => b.Soc) : 0; - var current = batteriesStatus.Select(b => b.Dc.Current).Aggregate(0m,(a, b) => a + b); - var voltage = batteriesStatus.Any() ? batteriesStatus.Average(b => b.Dc.Voltage) : 0; - var power = batteriesStatus.Select(b => b.Dc.Power).Aggregate(0m,(a, b) => a + b); - var busVoltage = batteriesStatus.Any() ? batteriesStatus.Average(b => b.BusVoltage): 0; - var batteryTemperature = batteriesStatus.Any() ? batteriesStatus.Average(b => b.Temperature): 0; - var heaterOn = batteriesStatus.Any() && batteriesStatus.Select(b => b.HeaterOn).Aggregate((a, b) => a | b); - var eocReached = batteriesStatus.All(b => b.EocReached); - var batteryCold = batteriesStatus.Any(b => b.BatteryCold); - var maxChargingPower = batteriesStatus.Select(b => b.MaxChargingPower).Aggregate(0m, (a, b) => a + b); - var maxDischargingPower = batteriesStatus.Select(b => b.MaxDischargingPower).Aggregate(0m, (a, b) => a + b); - - - return new AvgBatteriesStatus + var combined = stati.Count == 0 + ? null + : new Battery48TLStatus { - Soc = soc, - Current = current, - Voltage = voltage, - Power = power, - BusVoltage = busVoltage, - BatteryTemperature = batteryTemperature, - HeaterOn = heaterOn, - EocReached = eocReached, - BatteryCold = batteryCold, - MaxChargingPower = maxChargingPower, - MaxDischargingPower = maxDischargingPower + Soc = stati.Min(b => b.Soc), + Temperature = stati.Average(b => b.Temperature), + Dc = new DcBus + { + Voltage = stati.Average(b => b.Dc.Voltage), + Current = stati.Sum(b => b.Dc.Current), + }, + + Alarms = stati.SelectMany(b => b.Alarms).Distinct().ToList(), + Warnings = stati.SelectMany(b => b.Warnings).Distinct().ToList(), + + MaxChargingPower = stati.Sum(b => b.MaxChargingPower), + MaxDischargingPower = stati.Sum(b => b.MaxDischargingPower), + + Heating = stati.Any(b => b.Heating), + + AmberLed = LedState.Off, // not used for combined battery + BlueLed = LedState.Off, + RedLed = LedState.Off, + GreenLed = LedState.Off, + + CellsVoltage = stati.Average(b => b.CellsVoltage), + ConnectedToDc = stati.Any(b => b.ConnectedToDc), + + TemperatureState = stati.Any(b => b.TemperatureState == OperatingTemperature) // TODO: revisit when we have the overheated state + ? OperatingTemperature + : Cold, + + }; + + return new CombinedStatus + { + Combined = combined!, + Children = stati }; } } \ No newline at end of file diff --git a/csharp/App/SaliMax/src/Controller/StatusRecord.cs b/csharp/App/SaliMax/src/Controller/StatusRecord.cs index 53de658b8..9071f5976 100644 --- a/csharp/App/SaliMax/src/Controller/StatusRecord.cs +++ b/csharp/App/SaliMax/src/Controller/StatusRecord.cs @@ -5,18 +5,19 @@ using InnovEnergy.Lib.Devices.Battery48TL; using InnovEnergy.Lib.Devices.EmuMeter; using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc; using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc; +using InnovEnergy.Lib.StatusApi; namespace InnovEnergy.App.SaliMax.Controller; public record StatusRecord { - public TruConvertAcStatus? InverterStatus { get; init; } - public TruConvertDcStatus? DcDcStatus { get; init; } - public Battery48TLStatus[]? BatteriesStatus { get; set; } = Array.Empty(); // TODO remove static - public AvgBatteriesStatus? AvgBatteriesStatus { get; init; } - public EmuMeterStatus? GridMeterStatus { get; init; } - public SaliMaxRelayStatus? SaliMaxRelayStatus { get; init; } - public AmptStatus? AmptStatus { get; init; } - public EmuMeterStatus? AcInToAcOutMeterStatus { get; init; } - public SalimaxConfig SalimaxConfig { get; init; } = null!; + public TruConvertAcStatus? InverterStatus { get; init; } + public TruConvertDcStatus? DcDcStatus { get; init; } + public CombinedStatus? BatteriesStatus { get; init; } + + public EmuMeterStatus? GridMeterStatus { get; init; } + public SaliMaxRelayStatus? SaliMaxRelayStatus { get; init; } + public AmptStatus? AmptStatus { get; init; } + public EmuMeterStatus? AcInToAcOutMeterStatus { get; init; } + public SalimaxConfig SalimaxConfig { get; init; } = null!; } \ No newline at end of file diff --git a/csharp/App/SaliMax/src/Program.cs b/csharp/App/SaliMax/src/Program.cs index 229e3f0b8..d4d080a11 100644 --- a/csharp/App/SaliMax/src/Program.cs +++ b/csharp/App/SaliMax/src/Program.cs @@ -13,6 +13,7 @@ using InnovEnergy.Lib.Devices.EmuMeter; using InnovEnergy.Lib.Devices.Trumpf.TruConvertAc; using InnovEnergy.Lib.Devices.Trumpf.TruConvertDc; using InnovEnergy.Lib.Time.Unix; +using InnovEnergy.Lib.Utils; #pragma warning disable IL2026 @@ -41,14 +42,26 @@ internal static class Program { Console.WriteLine("Starting SaliMax"); + var batteryNodes = new Byte[] { 2, 3 }; + + var batteryTty = "/dev/ttyUSB0"; + + var relaysIp = "10.0.1.1"; + var truConvertAcIp = "10.0.2.1"; + var truConvertDcIp = "10.0.3.1"; + var gridMeterIp = "10.0.4.1"; + var internalMeter = "10.0.4.2"; + var amptIp = "10.0.5.1"; + + var s3Config = new S3Config { - Bucket = "saliomameiringen", - Region = "sos-ch-dk-2", - Provider = "exo.io", + Bucket = "saliomameiringen", + Region = "sos-ch-dk-2", + Provider = "exo.io", ContentType = "text/plain; charset=utf-8", - Key = "EXO2bf0cbd97fbfa75aa36ed46f", - Secret = "Bn1CDPqOG-XpDSbYjfIJxojcHTm391vZTc8z8l_fEPs" + Key = "EXO2bf0cbd97fbfa75aa36ed46f", + Secret = "Bn1CDPqOG-XpDSbYjfIJxojcHTm391vZTc8z8l_fEPs" }; #if DEBUG @@ -62,48 +75,42 @@ internal static class Program var firstBattery48TlDevice =Battery48TlDevice.Fake();; var salimaxConfig = new SalimaxConfig(); #else -#if BatteriesAllowed - var firstBattery48TlDevice = new Battery48TlDevice("/dev/ttyUSB0", 2); - var secondBattery48TlDevice = new Battery48TlDevice("/dev/ttyUSB0", 3); -#endif - var inverterDevice = new TruConvertAcDevice("192.168.1.2"); - var dcDcDevice = new TruConvertDcDevice("192.168.1.3"); - var gridMeterDevice = new EmuMeterDevice("192.168.1.241"); - var acInToAcOutMeterDevice = new EmuMeterDevice("192.168.1.241"); // TODO: use real device - var amptDevice = new AmptCommunicationUnit("192.168.1.249"); - var saliMaxRelaysDevice = new SaliMaxRelaysDevice("192.168.1.242"); + + var batteries = batteryNodes.Select(n => new Battery48TlDevice(batteryTty, n)).ToList(); + + + var inverterDevice = new TruConvertAcDevice(truConvertAcIp); + var dcDcDevice = new TruConvertDcDevice(truConvertDcIp); + + var gridMeterDevice = new EmuMeterDevice(gridMeterIp); + var acInToAcOutMeterDevice = new EmuMeterDevice(internalMeter); // TODO: use real device + + var amptDevice = new AmptCommunicationUnit(amptIp); + + var saliMaxRelaysDevice = new SaliMaxRelaysDevice(relaysIp); var salimaxConfig = new SalimaxConfig(); #endif // This is will be always add manually ? or do we need to read devices automatically in a range of IP @ -#if BatteriesAllowed - var battery48TlDevices = new[] { firstBattery48TlDevice, secondBattery48TlDevice }; -#endif - - var dcDcDevices = new[] { dcDcDevice }; - var inverterDevices = new[] { inverterDevice}; + StatusRecord ReadStatus() { -#if BatteriesAllowed - - var battery48TlStatusArray = battery48TlDevices.Select(b => b.ReadStatus()).NotNull().ToArray(); -#endif - // var dcDcStatusArray = dcDcDevices.Select(b => b.ReadStatus()).NotNull().ToArray(); + var combinedBatteryStatus = batteries + .Select(b => b.ReadStatus()) + .NotNull() + .ToList() + .Combine(); + + // var dcDcStatusArray = dcDcDevices.Select(b => b.ReadStatus()).NotNull().ToArray(); // var inverterStatusArray = inverterDevices.Select(b => b.ReadStatus()).NotNull().ToArray(); return new StatusRecord { InverterStatus = inverterDevice.ReadStatus(), DcDcStatus = dcDcDevice.ReadStatus(), -#if BatteriesAllowed - BatteriesStatus = battery48TlStatusArray, - AvgBatteriesStatus = AvgBatteriesStatus.ReadBatteriesStatus(battery48TlStatusArray), -#else - BatteriesStatus = null, - AvgBatteriesStatus = null, -#endif + BatteriesStatus = combinedBatteryStatus, AcInToAcOutMeterStatus = acInToAcOutMeterDevice.ReadStatus(), GridMeterStatus = gridMeterDevice.ReadStatus(), SaliMaxRelayStatus = saliMaxRelaysDevice.ReadStatus(), diff --git a/csharp/App/SaliMax/tunneltoProto.sh b/csharp/App/SaliMax/tunneltoProto.sh new file mode 100644 index 000000000..215e43c1d --- /dev/null +++ b/csharp/App/SaliMax/tunneltoProto.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +host=ie-entwicklung@10.2.3.115 + +tunnel() { + name=$1 + ip=$2 + rPort=$3 + lPort=$4 + + echo -n "localhost:$lPort $name " + ssh -nNTL "$lPort:$ip:$rPort" "$host" 2> /dev/null & + + until nc -vz 127.0.0.1 $lPort 2> /dev/null + do + echo -n . + sleep 0.3 + done + + echo "ok" +} + +echo "" + +tunnel "Trumpf Inverter (http) " 10.0.2.1 80 8001 +tunnel "Trumpf DCDC (http) " 10.0.3.1 80 8002 +tunnel "Ext Emu Meter (http) " 10.0.4.1 80 8003 +tunnel "Int Emu Meter (http) " 10.0.4.2 80 8004 +tunnel "AMPT (http) " 10.0.5.1 8080 8005 + +tunnel "Trumpf Inverter (modbus)" 10.0.2.1 502 5001 +tunnel "Trumpf DCDC (modbus) " 10.0.3.1 502 5002 +tunnel "Ext Emu Meter (modbus) " 10.0.4.1 502 5003 +tunnel "Int Emu Meter " 10.0.4.2 502 5004 +tunnel "AMPT (modbus) " 10.0.5.1 502 5005 + + + +echo +echo "press any key to close the tunnels ..." +read -r -n 1 -s +kill $(jobs -p) +echo "done" \ No newline at end of file diff --git a/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs b/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs index 6507ac32d..97462b720 100644 --- a/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs +++ b/csharp/Lib/Devices/Battery48TL/Battery48TLDevice.cs @@ -1,5 +1,6 @@ using InnovEnergy.Lib.Protocols.Modbus.Clients; using InnovEnergy.Lib.Protocols.Modbus.Connections; +using static InnovEnergy.Lib.Devices.Battery48TL.Constants; namespace InnovEnergy.Lib.Devices.Battery48TL; @@ -10,10 +11,10 @@ public class Battery48TlDevice public Battery48TlDevice(String device, Byte nodeId) { var serialConnection = new ModbusSerialConnection(device, - Constants.BaudRate, - Constants.Parity, - Constants.DataBits, - Constants.StopBits, + BaudRate, + Parity, + DataBits, + StopBits, Constants.Timeout); Modbus = new ModbusRtuClient(serialConnection, nodeId); @@ -34,7 +35,7 @@ public class Battery48TlDevice try { return Modbus - .ReadInputRegisters(Constants.BaseAddress, Constants.NoOfRegisters) + .ReadInputRegisters(BaseAddress, NoOfRegisters) .ParseBatteryStatus(); } catch (Exception e) diff --git a/csharp/Lib/Devices/Battery48TL/TemperatureState.cs b/csharp/Lib/Devices/Battery48TL/TemperatureState.cs index da34812e0..6bb71b4e1 100644 --- a/csharp/Lib/Devices/Battery48TL/TemperatureState.cs +++ b/csharp/Lib/Devices/Battery48TL/TemperatureState.cs @@ -4,5 +4,5 @@ public enum TemperatureState { Cold = 0, OperatingTemperature = 1, - Overheated =2, + Overheated = 2, } \ No newline at end of file diff --git a/csharp/Lib/StatusApi/BatteryStatus.cs b/csharp/Lib/StatusApi/BatteryStatus.cs index d512b931f..be2c8f0d5 100644 --- a/csharp/Lib/StatusApi/BatteryStatus.cs +++ b/csharp/Lib/StatusApi/BatteryStatus.cs @@ -12,5 +12,4 @@ public record BatteryStatus : IDcConnection public DcBus Dc { get; init; } public Percent Soc { get; init; } public Temperature Temperature { get; init; } -} - \ No newline at end of file +} \ No newline at end of file diff --git a/csharp/Lib/StatusApi/CombinedStatus.cs b/csharp/Lib/StatusApi/CombinedStatus.cs new file mode 100644 index 000000000..132f0c573 --- /dev/null +++ b/csharp/Lib/StatusApi/CombinedStatus.cs @@ -0,0 +1,12 @@ +namespace InnovEnergy.Lib.StatusApi; + +#pragma warning disable CS8618 + +public record CombinedStatus +{ + public T Combined { get; init; } + public IReadOnlyList Children { get; init; } + + public Boolean Available => Children.Any(); + +} \ No newline at end of file