diff --git a/csharp/App/VrmGrabber/Controller.cs b/csharp/App/VrmGrabber/Controller.cs index a21523d6c..03006cc92 100644 --- a/csharp/App/VrmGrabber/Controller.cs +++ b/csharp/App/VrmGrabber/Controller.cs @@ -3,17 +3,26 @@ using System.IdentityModel.Tokens.Jwt; using System.Web; using HandlebarsDotNet; using InnovEnergy.App.RemoteSupportConsole; -using static System.Text.Json.JsonSerializer; using InnovEnergy.App.VrmGrabber.Database; -using InnovEnergy.Lib.Victron.VictronVRM; using Microsoft.AspNetCore.Mvc; using FILE=System.IO.File; using VrmInstallation = InnovEnergy.Lib.Victron.VictronVRM.Installation; -using Installation = InnovEnergy.App.VrmGrabber.DataTypes.Installation; -using System.Diagnostics.CodeAnalysis; namespace InnovEnergy.App.VrmGrabber; +public record Install( + String Name, + String Ip, + Int64 Vrm, + String Identifier, + String Serial, + String EscapedName, + String Online, + String LastSeen, + Int64 NumBatteries, + String BatteryVersion +); + [Controller] public class Controller : ControllerBase { @@ -35,26 +44,45 @@ public class Controller : ControllerBase letter-spacing: 1px; font-family: sans-serif; font-size: 0.8rem; - position: absolute; top: 0; bottom: 0; left: 0; right: 0; + position: relative; top: 0; bottom: 0; left: 0; right: 0; } td, th { border: 1px solid rgb(190, 190, 190); padding: 5px 10px; + position: sticky; + top: 0px; + background: white; } td { text-align: left; + } + #managerTable { + overflow: hidden; } - + +
+ + + + + + + + + + + {{#inst}} {{> installations}} {{/inst}} -
NameGuiVRMGrafanaIdentifierLast SeenSerial#BatteriesFirmware-Version
"; + +
"; String partialSource = @"{{Name}} @@ -64,6 +92,8 @@ public class Controller : ControllerBase {{Identifier}} {{LastSeen}} {{Serial}} + {{NumBatteries}} + {{BatteryVersion}} "; @@ -74,27 +104,23 @@ public class Controller : ControllerBase Content = "

Please wait page is still loading

" }; - Handlebars.RegisterTemplate("installations", partialSource); var template = Handlebars.Compile(source); - // var insts = instList.Select(i => - // { - // var ip = Ip(i); - // return new Install( - // i.Name, - // ip[0], - // i.Vrm, - // i.Identifier, - // i.Serial, - // i.EscapedName, - // ip[1], - // LastSeen(i)); - // }); - - + var insts = instList.Select(i => new Install( + i.Name, + i.Ip, + i.Vrm, + i.Identifier, + i.Serial, + i.EscapedName, + i.Online, + DateTimeOffset.FromUnixTimeSeconds(Convert.ToInt64(i.LastSeen)).ToString(), + i.NumberOfBatteries, + i.BatteryFirmwareVersion)); + var data = new { - inst = instList + inst = insts }; var result = template(data); @@ -106,17 +132,6 @@ public class Controller : ControllerBase }; } - private String? LastSeen(Installation installation) - { - return Db.GetInstallationByIdentifier(installation.Identifier)?.Details.ToString(); - } - - [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] - public static String? Serial(Installation installation) - { - return Deserialize>(installation.Details).MachineSerial(); - } - // [HttpGet(nameof(GetInstallation))] // [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "")] // public Object GetInstallation(UInt64 serialNumber) diff --git a/csharp/App/VrmGrabber/DataTypes/Installation.cs b/csharp/App/VrmGrabber/DataTypes/Installation.cs index 8bcd30db2..86faf3d74 100644 --- a/csharp/App/VrmGrabber/DataTypes/Installation.cs +++ b/csharp/App/VrmGrabber/DataTypes/Installation.cs @@ -6,7 +6,7 @@ namespace InnovEnergy.App.VrmGrabber.DataTypes; public class Installation { - public Installation(String? argName, String? argIp, Int64 argVrm, String? argIdentifier, String? serial, String? urlEncode, String? online, String? lastSeen, String details) + public Installation(String? argName, String? argIp, Int64 argVrm, String? argIdentifier, String? serial, String? urlEncode, String? online, String? lastSeen, String details, Int64 numberOfBatteries, String batteryFirmwareVersion) { Name = argName; Ip = argIp; @@ -17,6 +17,8 @@ public class Installation Online = online; LastSeen = lastSeen; Details = details; + NumberOfBatteries = numberOfBatteries; + BatteryFirmwareVersion = batteryFirmwareVersion; } public Installation() @@ -26,11 +28,15 @@ public class Installation public String? Name { get; set;} public String? Ip { get; set;} public Int64 Vrm { get; set;} + + [PrimaryKey] public String? Identifier { get; set;} public String? Serial { get; set;} public String? EscapedName { get; set;} public String? Online { get; set;} - public String? LastSeen { get; set;} + public String? LastSeen { get; set;} + public Int64 NumberOfBatteries { get; set;} + public String? BatteryFirmwareVersion { get; set;} public String? Details { get; set; } //JSON } \ No newline at end of file diff --git a/csharp/App/VrmGrabber/Database/Db.cs b/csharp/App/VrmGrabber/Database/Db.cs index dcc0f10dc..89cb94b53 100644 --- a/csharp/App/VrmGrabber/Database/Db.cs +++ b/csharp/App/VrmGrabber/Database/Db.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Web; using CliWrap; using CliWrap.Buffered; @@ -69,7 +70,7 @@ public static partial class Db var installations = await user.GetInstallations(); // var returnDictionary = new Dictionary(); - foreach (var installation in installations.Take(20)) //TODO REMOVE TAKE + foreach (var installation in installations.Take(70)) //TODO REMOVE TAKE { Console.WriteLine(installation.Name); var details = await GetInstallationDetails(installation); @@ -83,7 +84,9 @@ public static partial class Db HttpUtility.UrlEncode(installation.Name), ip[1], details.Details.Last().Json["timestamp"].ToString(), - Serialize(details.Details)); + Serialize(details.Details), + await NumberOfBatteries(ip[0]), + await BatteryFirmwareVersion(ip[0])); if (GetInstallationByIdentifier(installation.Identifier) == null) { @@ -96,6 +99,36 @@ public static partial class Db } } + private static async Task BatteryFirmwareVersion(String? ip) + { + if (ip is null or "Unknown") return "Unknown"; + var pathToBattery = await ExecuteBufferedAsyncCommandOnIp(ip, "dbus-send --system --dest=com.victronenergy.system --type=method_call --print-reply /ServiceMapping/com_victronenergy_battery_1 com.victronenergy.BusItem.GetText"); + var command = $"dbus-send --system --dest={pathToBattery} --type=method_call --print-reply /FirmwareVersion com.victronenergy.BusItem.GetText"; + return await ExecuteBufferedAsyncCommandOnIp(ip, command); //todo fill me + } + + private static async Task NumberOfBatteries(String? ip) + { + if (ip is null or "Unknown") return 0; + var pathToBattery = await ExecuteBufferedAsyncCommandOnIp(ip, "dbus-send --system --dest=com.victronenergy.system --type=method_call --print-reply /ServiceMapping/com_victronenergy_battery_1 com.victronenergy.BusItem.GetText"); + var cmd = await ExecuteBufferedAsyncCommandOnIp(ip,$"dbus-send --system --dest={pathToBattery} --type=method_call --print-reply /NbOfBatteries com.victronenergy.BusItem.GetText" ); + + return cmd == "Unknown" ? 0 : Int64.Parse(cmd); //No Batteries can be found + } + + + private static async Task ExecuteBufferedAsyncCommandOnIp(String? ip, String command) + { + if (ip is null or "Unknown") return "Unknown"; + + var cmd = await Cli.Wrap("ssh") + .WithArguments($@"root@{ip}") + .AppendArgument("-o StrictHostKeyChecking=accept-new") + .AppendArgument(command) + .WithValidation(CommandResultValidation.None).ExecuteBufferedAsync(); + return cmd.StandardOutput.Split('"')[1]; + } + private static String?[] Ip(InstallationDetails details) { var online = "❌"; @@ -207,3 +240,11 @@ public class AccToken public UInt64 idUser { get; init;} public String token { get; init;} } + + +/* +dbus-send --system --dest=com.victronenergy.battery.ttyUSB1 --print-reply /FirmwareVersion \ +org.freedesktop.DBus.Properties.Get string:com.victronenergy.battery.ttyUSB1 + * + * + */ diff --git a/csharp/App/VrmGrabber/VrmGrabber.csproj b/csharp/App/VrmGrabber/VrmGrabber.csproj index 92c7a0262..fac230318 100644 --- a/csharp/App/VrmGrabber/VrmGrabber.csproj +++ b/csharp/App/VrmGrabber/VrmGrabber.csproj @@ -37,5 +37,11 @@ <_ContentIncludedByDefault Remove="wwwroot\index.html" /> + + + + PreserveNewest + + diff --git a/csharp/App/VrmGrabber/db.sqlite b/csharp/App/VrmGrabber/db.sqlite index eb43946b3..49c9c28a7 100644 Binary files a/csharp/App/VrmGrabber/db.sqlite and b/csharp/App/VrmGrabber/db.sqlite differ