using System.Text.RegularExpressions; using InnovEnergy.API.DataModel; using InnovEnergy.Lib.Utils; using InnovEnergy.Lib.Victron.VictronVRM; namespace InnovEnergy.API; public class VrmLink : IDisposable { private static readonly Regex RxSerial = new Regex(@"\s*\(\s*20\d\d-\d\d\d\d\d(\.\d)?\s*\)\s*", RegexOptions.Compiled | RegexOptions.Singleline); private Vrm Vrm { get; } private VrmLink(Vrm vrm) { Vrm = vrm; } public static async Task Login() { const String vrmUser = "victron@innov.energy"; const String vrmPwd = "NnoVctr201002"; var vrm = await Vrm.Login(vrmUser, vrmPwd); return new VrmLink(vrm); } public async Task SyncWithVrm(Data data) { var installationDetails = Vrm.GetInstallationDetailsAsync(); // var vpnIpLookup = Vpn.CreateVpnIpLookup(); // var vpnOnlineLookup = Vpn.CreateVpnOnlineLookup(); var vpnIpLookup = (String s) => "127.0.0.1"; var vpnOnlineLookup = (String s) => true; var vrmInstallationsById = data .Root .DescendantInstallations() .Where(d => (d.Element as VrmInstallation)?.UniqueId != null) .ToDictionary(d => d.Element.CastTo().UniqueId!); List DeleteExistingInstallation(InstallationDetails details) { vrmInstallationsById.TryGetValue(details.Identifier, out var existing); if (existing is null) return new List(); // if it already exists, delete it, but keep its users var installation = existing.Installation()!; var users = installation.Users; installation.Users = new List(); existing.Delete(); return users; } // SYNC await foreach (var i in installationDetails) { if (!i.IsActive) continue; var (name, path, ieSerial) = ParseVrmName(i); var users = DeleteExistingInstallation(i); var installation = new VrmInstallation { Name = name, Users = users, IeSerial = ieSerial, VrmId = i.IdSite, UniqueId = i.Identifier, FirmwareVersion = i.FirmwareVersion, SystemType = i.SystemType, MachineSerial = i.MachineSerial, MachineName = i.MachineName, // type: VenusGx, CCGX, etc. Tags = i.Tags, VpnIp = vpnIpLookup(i.MachineSerial), Online = vpnOnlineLookup(i.MachineSerial), }; if (i.MachineName is not null) await Vrm.AddTags(i.IdSite, i.MachineName); var folder = data.GetOrCreateFolder(path); folder.Add(installation); } // SORT foreach (var folder in data.Root.DescendantFolders().Select(d => d.Element).OfType()) { folder.Folders.Sort(); folder.Installations.Sort(); folder.Users.Sort(); var grouped = folder.Installations.OfType().GroupBy(i=>i.Name); foreach (var g in grouped.Where(g => g.Count() > 1)) foreach (var (vrmInstallation, n) in g.OrderBy(i => i.UniqueId).Select((i, n) => (i, n))) { vrmInstallation.Name += $" ({n + 1})"; } foreach (var installation in folder.Installations) installation.Users.Sort(); } } private static (String name, IReadOnlyList path, String? serial) ParseVrmName(InstallationDetails installationDetails) { var fullName = installationDetails.Name; var match = RxSerial.Match(fullName); // extract IeSerial from _entire_ fullname var serial = match.Success ? match.Value : null; fullName = RxSerial.Replace(fullName, ""); var split = fullName.Split('|', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries); var path = split.Length > 1 ? split.Skip(1).Reverse().ToArray(split.Length - 1) : new[] { "ie" }; var name = split.Length >= 1 ? split[0] : installationDetails.Identifier; return (name, path, serial); } public void Dispose() => Vrm.Dispose(); }