Fixed a bug that stopped the updating of installations
This commit is contained in:
parent
5eb373b78e
commit
c969b72a82
|
@ -1,16 +1,15 @@
|
||||||
using System.Data.Common;
|
using CliWrap;
|
||||||
using System.IdentityModel.Tokens.Jwt;
|
using CliWrap.Buffered;
|
||||||
using System.Web;
|
|
||||||
using HandlebarsDotNet;
|
using HandlebarsDotNet;
|
||||||
using InnovEnergy.App.RemoteSupportConsole;
|
|
||||||
using InnovEnergy.App.VrmGrabber.Database;
|
using InnovEnergy.App.VrmGrabber.Database;
|
||||||
|
using InnovEnergy.Lib.Utils;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using FILE=System.IO.File;
|
using FILE=System.IO.File;
|
||||||
using VrmInstallation = InnovEnergy.Lib.Victron.VictronVRM.Installation;
|
using VrmInstallation = InnovEnergy.Lib.Victron.VictronVRM.Installation;
|
||||||
|
|
||||||
namespace InnovEnergy.App.VrmGrabber;
|
namespace InnovEnergy.App.VrmGrabber;
|
||||||
|
|
||||||
public record Install(
|
public record InstallationToHtmlInterface(
|
||||||
String Name,
|
String Name,
|
||||||
String Ip,
|
String Ip,
|
||||||
Int64 Vrm,
|
Int64 Vrm,
|
||||||
|
@ -26,12 +25,17 @@ public record Install(
|
||||||
[Controller]
|
[Controller]
|
||||||
public class Controller : ControllerBase
|
public class Controller : ControllerBase
|
||||||
{
|
{
|
||||||
|
|
||||||
|
//Todo automatically grab newest version?
|
||||||
|
private const String FirmwareVersion = "VERSION";
|
||||||
|
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("/")]
|
[Route("/")]
|
||||||
[Produces("text/html")]
|
[Produces("text/html")]
|
||||||
public ActionResult Index()
|
public ActionResult Index()
|
||||||
{
|
{
|
||||||
String source = @"<head>
|
const String source = @"<head>
|
||||||
<style>
|
<style>
|
||||||
tbody {
|
tbody {
|
||||||
background-color: #e4f0f5;
|
background-color: #e4f0f5;
|
||||||
|
@ -84,8 +88,9 @@ public class Controller : ControllerBase
|
||||||
</table>
|
</table>
|
||||||
<div id='managerTable'>";
|
<div id='managerTable'>";
|
||||||
|
|
||||||
String partialSource =
|
|
||||||
@"<tr><td>{{Name}}</td>
|
|
||||||
|
const String partialSource = @"<tr><td>{{Name}}</td>
|
||||||
<td><a target='_blank' href=http://{{Ip}}>{{online}} {{Ip}}</a></td>
|
<td><a target='_blank' href=http://{{Ip}}>{{online}} {{Ip}}</a></td>
|
||||||
<td><a target='_blank' href=https://vrm.victronenergy.com/installation/{{Vrm}}/dashboard>VRM</a></td>
|
<td><a target='_blank' href=https://vrm.victronenergy.com/installation/{{Vrm}}/dashboard>VRM</a></td>
|
||||||
<td><a target='_blank' href='https://salidomo.innovenergy.ch/d/ENkNRQXmk/installation?refresh=5s&orgId=1&var-Installation={{EscapedName}}&kiosk=tv'>Grafana</a></td>
|
<td><a target='_blank' href='https://salidomo.innovenergy.ch/d/ENkNRQXmk/installation?refresh=5s&orgId=1&var-Installation={{EscapedName}}&kiosk=tv'>Grafana</a></td>
|
||||||
|
@ -94,11 +99,11 @@ public class Controller : ControllerBase
|
||||||
<td>{{Serial}}</td>
|
<td>{{Serial}}</td>
|
||||||
<td>{{NumBatteries}}</td>
|
<td>{{NumBatteries}}</td>
|
||||||
<td>{{BatteryVersion}}</td>
|
<td>{{BatteryVersion}}</td>
|
||||||
|
<td><a target='_blank' href=http://{{serverIp}}/UpdateBatteryFirmware/{{Ip}}>⬆️{{firmwareVersion}}</a></td>
|
||||||
</tr>";
|
</tr>";
|
||||||
|
|
||||||
|
var installationsInDb = Db.Installations.ToList();
|
||||||
var instList = Db.Installations.ToList();
|
if (installationsInDb.Count == 0) return new ContentResult
|
||||||
if (instList.Count == 0) return new ContentResult
|
|
||||||
{
|
{
|
||||||
ContentType = "text/html",
|
ContentType = "text/html",
|
||||||
Content = "<p>Please wait page is still loading</p>"
|
Content = "<p>Please wait page is still loading</p>"
|
||||||
|
@ -106,7 +111,7 @@ public class Controller : ControllerBase
|
||||||
|
|
||||||
Handlebars.RegisterTemplate("installations", partialSource);
|
Handlebars.RegisterTemplate("installations", partialSource);
|
||||||
var template = Handlebars.Compile(source);
|
var template = Handlebars.Compile(source);
|
||||||
var insts = instList.Select(i => new Install(
|
var installsForHtml = installationsInDb.Select(i => new InstallationToHtmlInterface(
|
||||||
i.Name,
|
i.Name,
|
||||||
i.Ip,
|
i.Ip,
|
||||||
i.Vrm,
|
i.Vrm,
|
||||||
|
@ -120,7 +125,9 @@ public class Controller : ControllerBase
|
||||||
|
|
||||||
var data = new
|
var data = new
|
||||||
{
|
{
|
||||||
inst = insts
|
inst = installsForHtml,
|
||||||
|
serverIp = "10.2.0.1",
|
||||||
|
firmwareVersion = FirmwareVersion
|
||||||
};
|
};
|
||||||
|
|
||||||
var result = template(data);
|
var result = template(data);
|
||||||
|
@ -132,6 +139,32 @@ public class Controller : ControllerBase
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet(nameof(UpdateBatteryFirmware))]
|
||||||
|
public async Task<ActionResult> UpdateBatteryFirmware(String installationIp, Int64 numOfBatteries)
|
||||||
|
{
|
||||||
|
//We need the DeviceName of the battery (ttyUSB?)
|
||||||
|
var pathToBattery = await Db.ExecuteBufferedAsyncCommandOnIp(installationIp, "dbus-send --system --dest=com.victronenergy.system --type=method_call --print-reply /ServiceMapping/com_victronenergy_battery_1 com.victronenergy.BusItem.GetText");
|
||||||
|
|
||||||
|
if (pathToBattery == "Failed") return new BadRequestResult();
|
||||||
|
|
||||||
|
SendNewBatteryFirmware(installationIp);
|
||||||
|
|
||||||
|
for (var batteryId = 0; batteryId < numOfBatteries; batteryId++)
|
||||||
|
{
|
||||||
|
var updateCommand = await Db.ExecuteBufferedAsyncCommandOnIp(installationIp, $"/opt/innovenergy/scripts/upload-bms-firmware {pathToBattery} {batteryId} /opt/innovenergy/bms-firmware/{FirmwareVersion}.bin");
|
||||||
|
if (updateCommand == "Failed") return new BadRequestResult();
|
||||||
|
}
|
||||||
|
return new AcceptedResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendNewBatteryFirmware(String installationIp)
|
||||||
|
{
|
||||||
|
Cli.Wrap("scp")
|
||||||
|
.WithArguments($@"{FirmwareVersion}.bin")
|
||||||
|
.AppendArgument($@"root@{installationIp}:/opt/innovenergy/bms-firmware/{FirmwareVersion}.bin")
|
||||||
|
.WithValidation(CommandResultValidation.None).ExecuteBufferedAsync();
|
||||||
|
}
|
||||||
// [HttpGet(nameof(GetInstallation))]
|
// [HttpGet(nameof(GetInstallation))]
|
||||||
// [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
|
// [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
|
||||||
// public Object GetInstallation(UInt64 serialNumber)
|
// public Object GetInstallation(UInt64 serialNumber)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Globalization;
|
using System.Reactive.Concurrency;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Reactive.Threading.Tasks;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using CliWrap;
|
using CliWrap;
|
||||||
using CliWrap.Buffered;
|
using CliWrap.Buffered;
|
||||||
|
@ -33,7 +35,7 @@ public static partial class Db
|
||||||
public static Dictionary<Installation, InstallationDetails> InstallationsAndDetails;
|
public static Dictionary<Installation, InstallationDetails> InstallationsAndDetails;
|
||||||
|
|
||||||
|
|
||||||
internal const String DbPath = "./db.sqlite";
|
private const String DbPath = "./db.sqlite";
|
||||||
|
|
||||||
private static SQLiteConnection Connection { get; } = new SQLiteConnection(DbPath);
|
private static SQLiteConnection Connection { get; } = new SQLiteConnection(DbPath);
|
||||||
|
|
||||||
|
@ -54,10 +56,10 @@ public static partial class Db
|
||||||
|
|
||||||
public static async Task UpdateDetailsAndInstallations()
|
public static async Task UpdateDetailsAndInstallations()
|
||||||
{
|
{
|
||||||
while (true)
|
do {
|
||||||
{
|
|
||||||
await UpdateInstallationsAndDetailsFromVrm(0);
|
await UpdateInstallationsAndDetailsFromVrm(0);
|
||||||
}
|
}
|
||||||
|
while (true) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
|
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
|
||||||
|
@ -70,7 +72,7 @@ public static partial class Db
|
||||||
var installations = await user.GetInstallations();
|
var installations = await user.GetInstallations();
|
||||||
|
|
||||||
// var returnDictionary = new Dictionary<VrmInstallation, InstallationDetails>();
|
// var returnDictionary = new Dictionary<VrmInstallation, InstallationDetails>();
|
||||||
foreach (var installation in installations.Take(70)) //TODO REMOVE TAKE
|
foreach (var installation in installations) //TODO REMOVE TAKE
|
||||||
{
|
{
|
||||||
Console.WriteLine(installation.Name);
|
Console.WriteLine(installation.Name);
|
||||||
var details = await GetInstallationDetails(installation);
|
var details = await GetInstallationDetails(installation);
|
||||||
|
@ -85,8 +87,8 @@ public static partial class Db
|
||||||
ip[1],
|
ip[1],
|
||||||
details.Details.Last().Json["timestamp"].ToString(),
|
details.Details.Last().Json["timestamp"].ToString(),
|
||||||
Serialize(details.Details),
|
Serialize(details.Details),
|
||||||
await NumberOfBatteries(ip[0]),
|
await NumberOfBatteries(ip[0], ip[1]),
|
||||||
await BatteryFirmwareVersion(ip[0]));
|
await BatteryFirmwareVersion(ip[0], ip[1]));
|
||||||
|
|
||||||
if (GetInstallationByIdentifier(installation.Identifier) == null)
|
if (GetInstallationByIdentifier(installation.Identifier) == null)
|
||||||
{
|
{
|
||||||
|
@ -99,34 +101,41 @@ public static partial class Db
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<String> BatteryFirmwareVersion(String? ip)
|
private static async Task<String> BatteryFirmwareVersion(String? ip, String? online)
|
||||||
{
|
{
|
||||||
if (ip is null or "Unknown") return "Unknown";
|
if (ip is null or "Unknown" || online == "❌") 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 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");
|
||||||
|
|
||||||
|
if (pathToBattery.StartsWith("Error")) return "Unknown";
|
||||||
|
|
||||||
|
|
||||||
var command = $"dbus-send --system --dest={pathToBattery} --type=method_call --print-reply /FirmwareVersion 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
|
return await ExecuteBufferedAsyncCommandOnIp(ip, command);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<Int64> NumberOfBatteries(String? ip)
|
private static async Task<Int64> NumberOfBatteries(String? ip, String? online)
|
||||||
{
|
{
|
||||||
if (ip is null or "Unknown") return 0;
|
if (ip is null or "Unknown" || online == "❌") 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 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");
|
||||||
|
|
||||||
|
if (pathToBattery.StartsWith("Error")) return 0;
|
||||||
|
|
||||||
var cmd = await ExecuteBufferedAsyncCommandOnIp(ip,$"dbus-send --system --dest={pathToBattery} --type=method_call --print-reply /NbOfBatteries 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
|
return cmd == "Failed" ? 0 : Int64.Parse(cmd); //No Batteries can be found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static async Task<String> ExecuteBufferedAsyncCommandOnIp(String? ip, String command)
|
public static async Task<String> ExecuteBufferedAsyncCommandOnIp(String? ip, String command)
|
||||||
{
|
{
|
||||||
if (ip is null or "Unknown") return "Unknown";
|
if (ip is null or "Unknown") return "Failed";
|
||||||
|
|
||||||
var cmd = await Cli.Wrap("ssh")
|
var cmd = await Cli.Wrap("ssh")
|
||||||
.WithArguments($@"root@{ip}")
|
.WithArguments($@"root@{ip}")
|
||||||
.AppendArgument("-o StrictHostKeyChecking=accept-new")
|
.AppendArgument("-o StrictHostKeyChecking=accept-new")
|
||||||
.AppendArgument(command)
|
.AppendArgument(command)
|
||||||
.WithValidation(CommandResultValidation.None).ExecuteBufferedAsync();
|
.WithValidation(CommandResultValidation.None).ExecuteBufferedAsync();
|
||||||
return cmd.StandardOutput.Split('"')[1];
|
return cmd.ExitCode == 0 ? cmd.StandardOutput.Split('"')[1] : cmd.StandardError;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String?[] Ip(InstallationDetails details)
|
private static String?[] Ip(InstallationDetails details)
|
||||||
|
|
Loading…
Reference in New Issue