From b727ef765a431414b27aea70e816f6f41bcbd343 Mon Sep 17 00:00:00 2001 From: Kim Date: Mon, 18 Sep 2023 13:21:39 +0200 Subject: [PATCH] Checking for loops in foldertree, getting only unique children now. Small Stability changes to VrmGrabber --- .../App/Backend/DataTypes/Methods/Folder.cs | 15 ++- .../Backend/DataTypes/Methods/Installation.cs | 2 +- csharp/App/Backend/DataTypes/Methods/User.cs | 6 +- .../DataTypes/TreeNode.EqualityComparer.cs | 25 ++++ csharp/App/VrmGrabber/Controller.cs | 2 +- csharp/App/VrmGrabber/Database/Db.cs | 2 +- csharp/Lib/Utils/GraphTraversal.cs | 116 ++++++++++++++++++ csharp/Lib/Utils/TreeTraversal.cs | 4 +- 8 files changed, 162 insertions(+), 10 deletions(-) create mode 100644 csharp/App/Backend/DataTypes/TreeNode.EqualityComparer.cs create mode 100644 csharp/Lib/Utils/GraphTraversal.cs diff --git a/csharp/App/Backend/DataTypes/Methods/Folder.cs b/csharp/App/Backend/DataTypes/Methods/Folder.cs index 8098b53c0..f2595d00b 100644 --- a/csharp/App/Backend/DataTypes/Methods/Folder.cs +++ b/csharp/App/Backend/DataTypes/Methods/Folder.cs @@ -31,13 +31,22 @@ public static class FolderMethods .NotNull(); } - public static IEnumerable ChildFolders(this Folder parent) + private static IEnumerable ChildFolders(this Folder parent) { + // Unsafe can give back loops return Db .Folders .Where(f => f.ParentId == parent.Id); } + + public static IEnumerable UniqueChildFolders(this Folder parent) + { + var set = new HashSet(Db.Folders, EqualityComparer.Default); + + return ChildFolders(parent).Where(set.Add); + } + public static IEnumerable ChildInstallations(this Folder parent) { return Db @@ -48,14 +57,14 @@ public static class FolderMethods public static IEnumerable DescendantFolders(this Folder parent) { return parent - .TraverseDepthFirstPreOrder(ChildFolders) + .TraverseDepthFirstPreOrder(UniqueChildFolders) .Skip(1); // skip self } public static IEnumerable DescendantFoldersAndSelf(this Folder parent) { return parent - .TraverseDepthFirstPreOrder(ChildFolders); + .TraverseDepthFirstPreOrder(UniqueChildFolders); } public static Boolean IsDescendantOf(this Folder folder, Folder ancestor) { diff --git a/csharp/App/Backend/DataTypes/Methods/Installation.cs b/csharp/App/Backend/DataTypes/Methods/Installation.cs index cf6bdb014..a57920436 100644 --- a/csharp/App/Backend/DataTypes/Methods/Installation.cs +++ b/csharp/App/Backend/DataTypes/Methods/Installation.cs @@ -138,7 +138,7 @@ public static class InstallationMethods public static String GetOrderNumbers(this Installation installation) { - return string.Join(", ", Db.OrderNumber2Installation + return String.Join(", ", Db.OrderNumber2Installation .Where(i => i.InstallationId == installation.Id) .Select(i => i.OrderNumber) .ToReadOnlyList()); diff --git a/csharp/App/Backend/DataTypes/Methods/User.cs b/csharp/App/Backend/DataTypes/Methods/User.cs index f1913ee99..c3beece1a 100644 --- a/csharp/App/Backend/DataTypes/Methods/User.cs +++ b/csharp/App/Backend/DataTypes/Methods/User.cs @@ -13,10 +13,10 @@ public static class UserMethods { public static IEnumerable AccessibleInstallations(this User user) { - var direct = user.DirectlyAccessibleInstallations(); + var direct = user.DirectlyAccessibleInstallations().ToList(); var fromFolders = user .AccessibleFolders() - .SelectMany(u => u.ChildInstallations()); + .SelectMany(u => u.ChildInstallations()).ToList(); return direct .Concat(fromFolders) @@ -35,7 +35,7 @@ public static class UserMethods { var folders = user.AccessibleFolders() as IEnumerable; - // user.AccessibleInstallations().ForEach(i => i.FillOrderNumbers()); + user.AccessibleInstallations().ForEach(i => i.FillOrderNumbers()); var installations = user.AccessibleInstallations(); return folders.Concat(installations); diff --git a/csharp/App/Backend/DataTypes/TreeNode.EqualityComparer.cs b/csharp/App/Backend/DataTypes/TreeNode.EqualityComparer.cs new file mode 100644 index 000000000..c5bf974c8 --- /dev/null +++ b/csharp/App/Backend/DataTypes/TreeNode.EqualityComparer.cs @@ -0,0 +1,25 @@ +using System.Diagnostics.CodeAnalysis; + +namespace InnovEnergy.App.Backend.DataTypes; + +public abstract partial class TreeNode +{ + private sealed class IdEqualityComparer : IEqualityComparer + { + public Boolean Equals(TreeNode x, TreeNode y) + { + if (ReferenceEquals(x, y)) return true; + if (ReferenceEquals(x, null)) return false; + if (ReferenceEquals(y, null)) return false; + if (x.GetType() != y.GetType()) return false; + return x.Id == y.Id; + } + + public Int32 GetHashCode(TreeNode obj) + { + return obj.Id.GetHashCode(); + } + } + + public static IEqualityComparer IdComparer { get; } = new IdEqualityComparer(); +} \ No newline at end of file diff --git a/csharp/App/VrmGrabber/Controller.cs b/csharp/App/VrmGrabber/Controller.cs index cf174de10..955e16563 100644 --- a/csharp/App/VrmGrabber/Controller.cs +++ b/csharp/App/VrmGrabber/Controller.cs @@ -195,7 +195,7 @@ th { /* header cell */ for (var batteryId = 3; batteryId < Int64.Parse(numberOfBatteries) + 2; batteryId++) { localCommand = localCommand.Append( - $" && /opt/innovenergy/scripts/upload-bms-firmware {batteryTtyName} {batteryId} /opt/innovenergy/{FirmwareVersion}.bin"); + $" && sleep 3m && /opt/innovenergy/scripts/upload-bms-firmware {batteryTtyName} {batteryId} /opt/innovenergy/{FirmwareVersion}.bin"); } #pragma warning disable CS4014 Db.ExecuteBufferedAsyncCommandOnIp(installationIp, localCommand) diff --git a/csharp/App/VrmGrabber/Database/Db.cs b/csharp/App/VrmGrabber/Database/Db.cs index 130740a53..1b05edd54 100644 --- a/csharp/App/VrmGrabber/Database/Db.cs +++ b/csharp/App/VrmGrabber/Database/Db.cs @@ -153,7 +153,7 @@ public static partial class Db var command = $"dbus-send --system --dest={pathToBattery.Split('"')[1]} --type=method_call --print-reply /FirmwareVersion com.victronenergy.BusItem.GetText"; var returnString = await ExecuteBufferedAsyncCommandOnIp(ip, command); var returnStringShortened = returnString.Split('"')[1]; - return returnStringShortened.Length > 5 ? "Unknown" : returnStringShortened; + return returnStringShortened.Length > 10 ? "Unknown" : returnStringShortened; } private static async Task NumberOfBatteries(String? ip, String? online) diff --git a/csharp/Lib/Utils/GraphTraversal.cs b/csharp/Lib/Utils/GraphTraversal.cs new file mode 100644 index 000000000..50a8345eb --- /dev/null +++ b/csharp/Lib/Utils/GraphTraversal.cs @@ -0,0 +1,116 @@ +using System.Diagnostics.CodeAnalysis; + +namespace InnovEnergy.Lib.Utils; + +public static class GraphTraversal +{ + public static IEnumerable TraverseDepthFirstPreOrder(T root, + Func> getChildren, +IEqualityComparer? comparer = null) + { + return Traverse(root, TreeTraversal.TraverseDepthFirstPreOrder, getChildren, comparer); + } + + + public static IEnumerable TraverseDepthFirstPostOrder(T root, + Func> getChildren, +IEqualityComparer? comparer = null) + { + return Traverse(root, TreeTraversal.TraverseDepthFirstPostOrder, getChildren, comparer); + } + + public static IEnumerable TraverseBreadthFirst(T root, + Func> getChildren, + IEqualityComparer? comparer = null) + { + return Traverse(root, TreeTraversal.TraverseBreadthFirst, getChildren, comparer); + } + + public static IEnumerable TraverseDepthFirstPreOrder(IEnumerable sources, + Func> getChildren, +IEqualityComparer? comparer = null) + { + return Traverse(sources, TreeTraversal.TraverseDepthFirstPreOrder, getChildren, comparer); + } + + + public static IEnumerable TraverseDepthFirstPostOrder(IEnumerable sources, + Func> getChildren, +IEqualityComparer? comparer = null) + { + return Traverse(sources, TreeTraversal.TraverseDepthFirstPostOrder, getChildren, comparer); + } + + public static IEnumerable TraverseBreadthFirst(IEnumerable sources, + Func> getChildren, +IEqualityComparer? comparer = null) + { + return Traverse(sources, TreeTraversal.TraverseBreadthFirst, getChildren, comparer); + } + + + private static IEnumerable Traverse(T root, + Func>,IEnumerable> traversor, + Func> getChildren, +IEqualityComparer? comparer = null) + { + var getUniqueChildren = GetUniqueChildren(getChildren, root, comparer); + return traversor(root, getUniqueChildren); + } + + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] + private static IEnumerable Traverse(IEnumerable sources, + Func>,IEnumerable> traversor, + Func> getChildren, + IEqualityComparer? comparer = null) + { + var set = new HashSet(sources, comparer ?? EqualityComparer.Default); + IEnumerable GetUniqueChildren(T n) => getChildren(n).Where(set.Add); + + return from s in sources + from e in traversor(s, GetUniqueChildren) + select e; + } + + // TODO: IEqualityComparer + public static IEnumerable<(T source, T target)> Edges(T node, Func> getChildren) + { + return Edges(node.AsSingleEnumerable(), getChildren); + } + + + // TODO: IEqualityComparer + public static IEnumerable<(T source, T target)> Edges(IEnumerable sources, + Func> getChildren) + { + var hs = new HashSet<(T source, T target)>(); + + IEnumerable<(T source, T target)> GetChildEdges((T source, T target) edge) + { + return getChildren(edge.target) + .Select(c => (edge.target, c)) + .Where(hs!.Add); + } + + return from src in sources.Select(s => (s, s)) + from e in TreeTraversal.TraverseDepthFirstPreOrder(src, GetChildEdges).Skip(1) + select e; + } + + private static Func> GetUniqueChildren(Func> getChildren, +T root, +IEqualityComparer? comparer) + { + return GetUniqueChildren(getChildren, root.AsSingleEnumerable(), comparer); + } + + private static Func> GetUniqueChildren(Func> getChildren, +IEnumerable sources, +IEqualityComparer? comparer) + { + var set = new HashSet(sources, comparer ?? EqualityComparer.Default); + return n => getChildren(n).Where(set.Add); + } + + +} \ No newline at end of file diff --git a/csharp/Lib/Utils/TreeTraversal.cs b/csharp/Lib/Utils/TreeTraversal.cs index 2a23eb887..edafa3326 100644 --- a/csharp/Lib/Utils/TreeTraversal.cs +++ b/csharp/Lib/Utils/TreeTraversal.cs @@ -1,3 +1,5 @@ +using InnovEnergy.Lib.Utils.Reflection; + namespace InnovEnergy.Lib.Utils; public static class TreeTraversal @@ -77,7 +79,7 @@ public static class TreeTraversal var stack = new Stack>(); var it = root.AsSingleEnumerator(); it.MoveNext(); - + while (true) { //////// going down ////////