using System.Diagnostics.CodeAnalysis; using InnovEnergy.Lib.Utils; using InnovEnergy.WireFormat.VictronV1; namespace InnovEnergy.VenusLogger; internal static class Devices { public static Maybe Combine(this DeviceType deviceType, params Maybe[] devices) { return devices .Flatten() .Combine(deviceType); } public static Maybe Combine(this IEnumerable devices, DeviceType deviceType) { var devs = devices as IReadOnlyCollection ?? devices.ToList(); return devs.Combine(deviceType); } public static Maybe Combine(this IReadOnlyCollection devices, DeviceType deviceType) { return devices .EquivalentDevice(deviceType) .Do(d => d.Devices.Add(devices)); // Maybe; } public static Maybe EquivalentDevice(this DeviceType deviceType, params Maybe[] devices) { return devices .Flatten() .EquivalentDevice(deviceType); } public static Maybe EquivalentDevice(this IEnumerable devices, DeviceType deviceType) { var devs = devices as IReadOnlyCollection ?? devices.ToList(); return devs.EquivalentDevice(deviceType); } public static Maybe EquivalentDevice(this IReadOnlyCollection devices, DeviceType deviceType) { if (devices.Count <= 0) return null; if (devices.Count == 1) return new Device { Type = deviceType, Phases = { devices.First().Phases } }; var voltages = devices.GetPhaseVoltages(); var phases = voltages.Select((v, phase) => new Phase { Voltage = v, Current = devices.Sum(d => d.Phases[phase].Current), Power = devices.Sum(d => d.Phases[phase].Power), }); return new Device { Type = deviceType, Phases = { phases } }; } public static Device ReversePhases(this Device device) { device.Phases.ForEach(p => { p.Current = -p.Current; p.Power = -p.Power; }); return device; } [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] private static IEnumerable GetPhaseVoltages(this IReadOnlyCollection devices) { // TODO: warning if voltages unequal? var nPhases = devices.Max(d => d.Phases.Count); var phases = Enumerable.Range(0, nPhases); var voltages = phases .Select(AverageVoltage) .ToList(); if (nPhases != devices.Min(d => d.Phases.Count)) EqualizeNumberOfPhases(); return voltages; Single AverageVoltage(Int32 phase) { return devices .Where(d => d.Phases.Count > phase) .Average(d => d.Phases[phase].Voltage); } void EqualizeNumberOfPhases() { foreach (var phase in phases) foreach (var device in devices.Where(d => d.Phases.Count <= phase)) { device.Phases.Add(new Phase { Current = 0, Voltage = voltages[phase] }); } } } }