using CliWrap; using CliWrap.Buffered; using InnovEnergy.Lib.Utils; using static InnovEnergy.App.BmsTunnel.CliPrograms; namespace InnovEnergy.App.BmsTunnel; using Nodes = IReadOnlyList; public static class BatteryTty { const String DevDir = "/dev"; public static async Task GetTty() { Console.WriteLine("searching battery connection..."); return await GetTtyFromDBus() ?? await GetTtyFromDev(); } private static async Task GetTtyFromDev() { var ttys = await FileSystem .Local .GetFiles(DevDir, FileType.CharacterDevice); var candidateTtys = ttys .Where(f => f.StartsWith(DevDir + "/ttyUSB")) .NotNull() .ToList(); if (!candidateTtys.Any()) { Console.WriteLine("no USB converter cable attached!"); return null; } if (candidateTtys.Count == 1) return candidateTtys[0]; return "Select TTY:".ChooseFrom(candidateTtys); } private static async Task GetTtyFromDBus() { var tty = await LsDBus .ExecuteBufferedAsync() .Select(ParseBatteryTty); if (tty == null) return null; Console.WriteLine("found battery on DBus"); return $"{DevDir}/{tty}"; } private static CommandTask GetNodes(String tty) { const String defaultArgs = "--system --print-reply --type=method_call / com.victronenergy.BusItem.GetValue"; return DBusSend .AppendArgument($"--dest=com.victronenergy.battery.{tty}") .AppendArgument(defaultArgs) .ExecuteBufferedAsync() .Select(ParseBatteryNodes); } private static Nodes ParseBatteryNodes(BufferedCommandResult result) { return result .StandardOutput .Split(Environment.NewLine) .Where(l => l.Contains("_Battery/")) .Select(l => l.Split('/')[1]) .Where(n => Byte.TryParse(n, out _)) .Select(Byte.Parse) .Distinct() .OrderBy(n => n) .ToList(); } private static String? ParseBatteryTty(BufferedCommandResult result) { return result .StandardOutput .Split(Environment.NewLine) .Where(l => l.Contains("com.victronenergy.battery.")) .SelectMany(l => l.Split('.')) .LastOrDefault(); } }