@page "/" @using InverterMon.Shared.Models @using System.Text.Json @implements IDisposable Dashboard @if (status is not null) {
@if (status.GridUsageWatts > 100) {
Grid Usage
@status.GridUsageWatts
W
}
Output Load
@status.LoadWatts
W
@status.OutputVoltage
V
@(status.WorkingMode)
@status.LoadCurrent
A
Solar Power
@status.PVInputWatt
W
@status.PVInputVoltage
V
@status.PVInputCurrent
A
Battery
Charging
@status.BatteryChargeWatts
W
@status.BatteryChargeCurrent
A
@GetChargeMode()
@status.BatteryVoltage
V
@GetCRate() C
Discharging
@status.BatteryDischargeWatts
W
@status.BatteryDischargeCurrent
A
} @code{ private static event Action? onStatusUpdated; private static event Action? onStatusRetrievalError; private static InverterStatus? status; protected override void OnInitialized() { onStatusUpdated += UpdateState; onStatusRetrievalError += NullifyStatus; } private void NullifyStatus() { status = null; StateHasChanged(); } private void UpdateState(InverterStatus? s) { status = s; StateHasChanged(); } public void Dispose() { onStatusUpdated -= UpdateState; onStatusRetrievalError -= NullifyStatus; } public static async Task StartStatusStreaming(string basePath) { //note: only reason we have a full-time stream download is because there's a bug in // blazor-wasm that doesn't close the fetch http requests when streaming is involved. // and it leads to a new stream download being created everytime a page is initialized. // which leads to a memory leak/ connection exhaustion. using var client = new HttpClient(); client.BaseAddress = new(basePath); client.Timeout = TimeSpan.FromSeconds(5); var retryDelay = 1000; while (true) { try { using var request = new HttpRequestMessage(HttpMethod.Get, "api/status"); request.SetBrowserResponseStreamingEnabled(true); using var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); response.EnsureSuccessStatusCode(); using var stream = await response.Content.ReadAsStreamAsync(); await foreach (var s in JsonSerializer.DeserializeAsyncEnumerable( stream, new JsonSerializerOptions { PropertyNameCaseInsensitive = true, DefaultBufferSize = 64 })) { onStatusUpdated?.Invoke(s); retryDelay = 1000; } } catch (Exception) { onStatusRetrievalError?.Invoke(); await Task.Delay(retryDelay); retryDelay += 500; } } } private static double GetCRate() { if (status?.BatteryChargeCRate > 0) return status.BatteryChargeCRate; if (status?.BatteryDischargeCRate > 0) return status.BatteryDischargeCRate; return 0; } private static string GetChargeMode() => status?.ChargeMode is ChargeMode.NONE ? "VOLTAGE" : status?.ChargeMode.ToString() ?? string.Empty; }