set settings
This commit is contained in:
parent
b642498a60
commit
ef7fff7302
@ -7,7 +7,7 @@
|
||||
|
||||
<PageTitle>JK BMS Status</PageTitle>
|
||||
|
||||
<Loader Enabled=@(status is null) />
|
||||
<Loader Enabled=@(status is null)/>
|
||||
|
||||
@if (status is not null)
|
||||
{
|
||||
@ -50,7 +50,7 @@
|
||||
@if (status.AvgCurrentAmps == 0)
|
||||
{
|
||||
<div class="fs-5 m-0 p-0 text-muted">
|
||||
Holding<br />Voltage
|
||||
Holding<br/>Voltage
|
||||
</div>
|
||||
}
|
||||
@if (status.IsWarning)
|
||||
@ -134,13 +134,14 @@
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
onStatusUpdated += UpdateState;
|
||||
onStatusRetrievalError += NullifyStatus;
|
||||
onStatusRetrievalError += NullifyStatus;
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var st = await Js.LoadStateAsync<ClientSettings>();
|
||||
if(st is null)
|
||||
|
||||
if (st is null)
|
||||
{
|
||||
await Js.SaveStateAsync(state);
|
||||
}
|
||||
@ -168,6 +169,7 @@
|
||||
{
|
||||
return status!.GetTimeString();
|
||||
}
|
||||
|
||||
return $"{status!.TimeHrs} Hrs {status.TimeMins} Mins";
|
||||
}
|
||||
|
||||
@ -175,10 +177,12 @@
|
||||
{
|
||||
if (state.ShowCapacityKwh)
|
||||
{
|
||||
var avlCap = Math.Round((status!.AvailableCapacity * status.PackNominalVoltage) / 1000, 1);
|
||||
var packCap = Math.Round((status!.PackCapacity * status.PackNominalVoltage) / 1000, 1);
|
||||
var avlCap = Math.Round(status!.AvailableCapacity * status.PackNominalVoltage / 1000, 1);
|
||||
var packCap = Math.Round(status!.PackCapacity * status.PackNominalVoltage / 1000, 1);
|
||||
|
||||
return $"{avlCap} kWh / {packCap} kWh";
|
||||
}
|
||||
|
||||
return $"{Math.Round(status!.AvailableCapacity, 1)} Ah / {status!.PackCapacity} Ah";
|
||||
}
|
||||
|
||||
@ -207,11 +211,9 @@
|
||||
// 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
|
||||
{
|
||||
BaseAddress = new(basePath),
|
||||
Timeout = TimeSpan.FromSeconds(5)
|
||||
};
|
||||
using var client = new HttpClient();
|
||||
client.BaseAddress = new(basePath);
|
||||
client.Timeout = TimeSpan.FromSeconds(5);
|
||||
|
||||
var retryDelay = 1000;
|
||||
|
||||
@ -231,10 +233,10 @@
|
||||
JsonSerializer.DeserializeAsyncEnumerable<BMSStatus>(
|
||||
stream,
|
||||
new JsonSerializerOptions
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
DefaultBufferSize = 64
|
||||
}))
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
DefaultBufferSize = 64
|
||||
}))
|
||||
{
|
||||
onStatusUpdated?.Invoke(s);
|
||||
retryDelay = 1000;
|
||||
|
||||
@ -265,7 +265,7 @@
|
||||
|
||||
@code{
|
||||
private CurrentSettings? settings;
|
||||
private Button currentButton = Button.None;
|
||||
private Button? currentButton;
|
||||
private bool isSuccess;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
@ -274,7 +274,7 @@
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task SetChargePriority(string priority)
|
||||
private async Task SetChargePriority(byte priority)
|
||||
{
|
||||
isSuccess = false;
|
||||
|
||||
@ -297,7 +297,7 @@
|
||||
|
||||
break;
|
||||
default:
|
||||
currentButton = Button.None;
|
||||
currentButton = null;
|
||||
|
||||
break;
|
||||
}
|
||||
@ -310,7 +310,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetOutputPriority(string priority)
|
||||
private async Task SetOutputPriority(byte priority)
|
||||
{
|
||||
isSuccess = false;
|
||||
|
||||
@ -319,7 +319,7 @@
|
||||
OutputPriority.SolarFirst => Button.OpSolarFirst,
|
||||
OutputPriority.SolarBatteryUtility => Button.OpSolarBatteryUtility,
|
||||
OutputPriority.UtilityFirst => Button.OpUtilityFirst,
|
||||
_ => Button.None
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (await Http.GetStringAsync($"api/settings/set-setting/{Setting.OutputPriority}/{priority}") == "true")
|
||||
@ -332,7 +332,7 @@
|
||||
private async Task SetVoltage(Setting setting)
|
||||
{
|
||||
isSuccess = false;
|
||||
decimal value = 0;
|
||||
double value = 0;
|
||||
|
||||
switch (setting)
|
||||
{
|
||||
@ -362,19 +362,19 @@
|
||||
|
||||
break;
|
||||
default:
|
||||
currentButton = Button.None;
|
||||
currentButton = null;
|
||||
|
||||
break;
|
||||
}
|
||||
;
|
||||
|
||||
if (await Http.GetStringAsync($"api/settings/set-setting/{setting}/{value:00.0}") == "true")
|
||||
if (await Http.GetStringAsync($"api/settings/set-setting/{setting}/{value}") == "true")
|
||||
{
|
||||
isSuccess = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SetSetting(Setting settingName, string value)
|
||||
private async Task SetSetting(Setting settingName, byte value)
|
||||
{
|
||||
if (await Http.GetStringAsync($"api/settings/set-setting/{settingName}/{value}") == "true")
|
||||
{
|
||||
@ -382,7 +382,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLocalSetting(Setting settingName, string value)
|
||||
private void UpdateLocalSetting(Setting settingName, byte value)
|
||||
{
|
||||
switch (settingName)
|
||||
{
|
||||
@ -411,7 +411,7 @@
|
||||
isSuccess = false;
|
||||
await Http.PostAsJsonAsync("api/settings/set-system-spec", settings!.SystemSpec);
|
||||
isSuccess = true;
|
||||
currentButton = Button.None;
|
||||
currentButton = null;
|
||||
}
|
||||
|
||||
private string Spinner(Button button)
|
||||
@ -424,7 +424,7 @@
|
||||
? "visually-hidden"
|
||||
: "";
|
||||
|
||||
private string Success(Button button, string currentValue, string settingValue)
|
||||
private string Success(Button button, byte currentValue, byte settingValue)
|
||||
=> (currentButton == button && isSuccess) || currentValue == settingValue
|
||||
? "oi oi-circle-check text-success"
|
||||
: "";
|
||||
@ -432,16 +432,15 @@
|
||||
private string Sanitize(string value)
|
||||
=> value.StartsWith("0") ? value[1..] : value;
|
||||
|
||||
private enum Button
|
||||
private enum Button : byte
|
||||
{
|
||||
None = 0,
|
||||
ChOnlySolar = 1,
|
||||
ChSolarFirst = 2,
|
||||
ChSolarAndUtility = 3,
|
||||
ChUtilityFirst = 4,
|
||||
OpUtilityFirst = 5,
|
||||
OpSolarFirst = 6,
|
||||
OpSolarBatteryUtility = 7,
|
||||
OpUtilityFirst = 1, //never change this value
|
||||
OpSolarFirst = 2, //never change this value
|
||||
OpSolarBatteryUtility = 3, //never change this value
|
||||
ChOnlySolar = 4,
|
||||
ChSolarFirst = 5,
|
||||
ChSolarAndUtility = 6,
|
||||
ChUtilityFirst = 7,
|
||||
UpdateUserSettings = 8,
|
||||
BackToGridVoltage = 9,
|
||||
BackToBattery = 10,
|
||||
|
||||
@ -6,7 +6,7 @@ namespace InverterMon.Server.Endpoints.GetStatus;
|
||||
|
||||
public class Endpoint : EndpointWithoutRequest<object>
|
||||
{
|
||||
public FelicitySolarInverter Inverter { get; set; }
|
||||
public FelicitySolarInverter Inverter { get; set; } = null!;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
@ -28,25 +28,25 @@ public class Endpoint : EndpointWithoutRequest<object>
|
||||
|
||||
async IAsyncEnumerable<InverterStatus> GetDataStream([EnumeratorCancellation] CancellationToken c)
|
||||
{
|
||||
var blank = new InverterStatus();
|
||||
|
||||
while (!c.IsCancellationRequested)
|
||||
{
|
||||
if (Env.IsDevelopment())
|
||||
{
|
||||
var status = new InverterStatus();
|
||||
status.OutputVoltage = Random.Shared.Next(240);
|
||||
status.LoadWatts = Random.Shared.Next(3500);
|
||||
status.LoadPercentage = Random.Shared.Next(100);
|
||||
status.BatteryVoltage = Random.Shared.Next(24);
|
||||
status.BatteryChargeCurrent = Random.Shared.Next(20);
|
||||
status.BatteryDischargeCurrent = Random.Shared.Next(300);
|
||||
status.HeatSinkTemperature = Random.Shared.Next(300);
|
||||
status.PVInputCurrent = Random.Shared.Next(300);
|
||||
status.PVInputVoltage = Random.Shared.Next(300);
|
||||
status.PVInputWatt = Random.Shared.Next(1000);
|
||||
status.PV_MaxCapacity = 1000;
|
||||
status.BatteryCapacity = 100;
|
||||
var status = new InverterStatus
|
||||
{
|
||||
OutputVoltage = Random.Shared.Next(240),
|
||||
LoadWatts = Random.Shared.Next(3500),
|
||||
LoadPercentage = Random.Shared.Next(100),
|
||||
BatteryVoltage = Random.Shared.Next(24),
|
||||
BatteryChargeCurrent = Random.Shared.Next(20),
|
||||
BatteryDischargeCurrent = Random.Shared.Next(300),
|
||||
HeatSinkTemperature = Random.Shared.Next(300),
|
||||
PVInputCurrent = Random.Shared.Next(300),
|
||||
PVInputVoltage = Random.Shared.Next(300),
|
||||
PVInputWatt = Random.Shared.Next(1000),
|
||||
PV_MaxCapacity = 1000,
|
||||
BatteryCapacity = 100
|
||||
};
|
||||
|
||||
yield return status;
|
||||
}
|
||||
|
||||
@ -4,6 +4,11 @@ using InverterMon.Shared.Models;
|
||||
|
||||
namespace InverterMon.Server.Endpoints.PVLog.GetPVForDay;
|
||||
|
||||
public class Request
|
||||
{
|
||||
public int DayNumber { get; set; }
|
||||
}
|
||||
|
||||
public class Endpoint : Endpoint<Request, PVDay>
|
||||
{
|
||||
public Database Db { get; set; }
|
||||
@ -21,7 +26,7 @@ public class Endpoint : Endpoint<Request, PVDay>
|
||||
|
||||
if (pvDay is null)
|
||||
{
|
||||
await SendNotFoundAsync();
|
||||
await SendNotFoundAsync(c);
|
||||
|
||||
return;
|
||||
}
|
||||
@ -34,8 +39,6 @@ public class Endpoint : Endpoint<Request, PVDay>
|
||||
TotalWattHours = Random.Shared.Next(3000)
|
||||
};
|
||||
|
||||
//pvDay.AllocateBuckets(6, 18);
|
||||
|
||||
for (var i = 0; i < 97; i++)
|
||||
pvDay.WattPeaks.Add(i.ToString(), Random.Shared.Next(2000));
|
||||
}
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
namespace InverterMon.Server.Endpoints.PVLog.GetPVForDay;
|
||||
|
||||
public class Request
|
||||
{
|
||||
public int DayNumber { get; set; }
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
using InverterMon.Server.Persistence.Settings;
|
||||
using InverterMon.Server.InverterService;
|
||||
using InverterMon.Server.Persistence.Settings;
|
||||
using InverterMon.Shared.Models;
|
||||
|
||||
namespace InverterMon.Server.Endpoints.Settings.GetSettingValues;
|
||||
@ -6,6 +7,7 @@ namespace InverterMon.Server.Endpoints.Settings.GetSettingValues;
|
||||
public class Endpoint : EndpointWithoutRequest<CurrentSettings>
|
||||
{
|
||||
public UserSettings UserSettings { get; set; }
|
||||
public FelicitySolarInverter Inverter { get; set; }
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
@ -15,29 +17,48 @@ public class Endpoint : EndpointWithoutRequest<CurrentSettings>
|
||||
|
||||
public override async Task HandleAsync(CancellationToken c)
|
||||
{
|
||||
//todo: get values from inverter and send to client
|
||||
if (Env.IsDevelopment())
|
||||
{
|
||||
var res = new CurrentSettings
|
||||
{
|
||||
BackToBatteryVoltage = 48.1,
|
||||
BackToGridVoltage = 48.2,
|
||||
FloatChargeVoltage = 48.3,
|
||||
ChargePriority = ChargePriority.OnlySolar,
|
||||
DischargeCuttOffVoltage = 48.4,
|
||||
BulkChargeVoltage = 48.5,
|
||||
MaxACChargeCurrent = 10,
|
||||
MaxCombinedChargeCurrent = 20,
|
||||
OutputPriority = OutputPriority.SolarFirst,
|
||||
SystemSpec = UserSettings.ToSystemSpec()
|
||||
};
|
||||
await SendAsync(res, cancellation: c);
|
||||
|
||||
// var cmd = new GetSettings();
|
||||
// cmd.Result.SystemSpec = UserSettings.ToSystemSpec();
|
||||
//
|
||||
// if (Env.IsDevelopment())
|
||||
// {
|
||||
// cmd.Result.ChargePriority = "03";
|
||||
// cmd.Result.MaxACChargeCurrent = "10";
|
||||
// cmd.Result.MaxCombinedChargeCurrent = "020";
|
||||
// cmd.Result.OutputPriority = "02";
|
||||
// cmd.Result.BulkChargeVoltage = 27.1m;
|
||||
// await SendAsync(cmd.Result);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// Queue.AddCommands(cmd);
|
||||
//
|
||||
// await cmd.WhileProcessing(c);
|
||||
//
|
||||
// if (cmd.IsComplete)
|
||||
// await SendAsync(cmd.Result);
|
||||
// else
|
||||
// ThrowError("Unable to read settings in a timely manner!");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var data = Inverter.ReadSettings();
|
||||
var res = new CurrentSettings
|
||||
{
|
||||
BackToBatteryVoltage = data.BatteryBackToDischargeVoltage,
|
||||
BackToGridVoltage = data.BatteryBackToChargeVoltage,
|
||||
BulkChargeVoltage = data.BatteryCvChargingVoltage,
|
||||
ChargePriority = data.ChargingSourcePriority,
|
||||
DischargeCuttOffVoltage = data.BatteryCutOffVoltage,
|
||||
FloatChargeVoltage = data.BatteryFloatingChargingVoltage,
|
||||
MaxACChargeCurrent = data.MaxAcChargingCurrent,
|
||||
MaxCombinedChargeCurrent = data.MaxChargingCurrent,
|
||||
OutputPriority = data.OutputSourcePriority,
|
||||
SystemSpec = UserSettings.ToSystemSpec()
|
||||
};
|
||||
await SendAsync(res, cancellation: c);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError("Unable to read settings from inverter. Details: [{msg}]", e.Message);
|
||||
ThrowError("Unable to read settings from inverter!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,20 +1,33 @@
|
||||
namespace InverterMon.Server.Endpoints.Settings.SetSettingValue;
|
||||
using InverterMon.Server.InverterService;
|
||||
|
||||
namespace InverterMon.Server.Endpoints.Settings.SetSettingValue;
|
||||
|
||||
public class Endpoint : Endpoint<Shared.Models.SetSetting, bool>
|
||||
{
|
||||
public FelicitySolarInverter Inverter { get; set; }
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Get("settings/set-setting/{Command}/{Value}");
|
||||
Get("settings/set-setting/{Setting}/{Value}");
|
||||
AllowAnonymous();
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(Shared.Models.SetSetting r, CancellationToken c)
|
||||
{
|
||||
//todo: set settings using inveter
|
||||
if (Env.IsDevelopment())
|
||||
{
|
||||
await SendAsync(true, cancellation: c);
|
||||
|
||||
// var cmd = new InverterService.Commands.SetSetting(r.Command, r.Value);
|
||||
// Queue.AddCommands(cmd);
|
||||
// await cmd.WhileProcessing(c);
|
||||
// await SendAsync(cmd.Result);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Inverter.SetSetting(r.Setting, r.Value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await SendAsync(false, cancellation: c);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
// using InverterMon.Shared.Models;
|
||||
//
|
||||
// namespace InverterMon.Server.InverterService;
|
||||
//
|
||||
// public class CurrentStatus
|
||||
// {
|
||||
// public InverterStatus Result { get; set; }
|
||||
// }
|
||||
@ -5,20 +5,6 @@ using InverterMon.Shared.Models;
|
||||
|
||||
namespace InverterMon.Server.InverterService;
|
||||
|
||||
// sealed class StatusData
|
||||
// {
|
||||
// public int WorkingMode { get; set; }
|
||||
// public int BatteryChargingStage { get; set; }
|
||||
// public double BatteryVoltage { get; set; }
|
||||
// public int BatteryCurrent { get; set; }
|
||||
// public int BatteryPower { get; set; }
|
||||
// public double AcOutputVoltage { get; set; }
|
||||
// public int AcOutputActivePower { get; set; }
|
||||
// public int LoadPercentage { get; set; }
|
||||
// public double PvInputVoltage { get; set; }
|
||||
// public int PvInputPower { get; set; }
|
||||
// }
|
||||
|
||||
sealed class SettingsData
|
||||
{
|
||||
public double BatteryCutOffVoltage { get; set; }
|
||||
@ -32,21 +18,32 @@ sealed class SettingsData
|
||||
public byte MaxAcChargingCurrent { get; set; }
|
||||
}
|
||||
|
||||
[SuppressMessage("Performance", "CA1822:Mark members as static")]
|
||||
[SuppressMessage("Performance", "CA1822:Mark members as static"),
|
||||
SuppressMessage("ReSharper", "MemberCanBeMadeStatic.Global")]
|
||||
public sealed class FelicitySolarInverter
|
||||
{
|
||||
public InverterStatus Status { get; private set; }
|
||||
public InverterStatus Status { get; } = new();
|
||||
|
||||
const byte SlaveAddress = 0x01;
|
||||
static SerialPort _serialPort = null!;
|
||||
|
||||
internal void Connect(string portName)
|
||||
internal bool Connect(string portName)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_serialPort = new(portName, 2400, Parity.None, 8, StopBits.One);
|
||||
_serialPort.Open();
|
||||
|
||||
try
|
||||
{
|
||||
_serialPort.Open();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static byte[]? _cachedStatusFrame;
|
||||
@ -60,11 +57,8 @@ public sealed class FelicitySolarInverter
|
||||
{
|
||||
var regs = ReadRegisters(StatusStartAddress, StatusRegisterCount);
|
||||
|
||||
// var status = new StatusData
|
||||
// {
|
||||
// WorkingMode = regs[0], // 0x1101: Working mode (offset 0)
|
||||
// BatteryChargingStage = regs[1], // 0x1102: Battery charging stage (offset 1)
|
||||
// };
|
||||
|
||||
Status.BatteryVoltage = regs[7] / 100.0; // 0x1108: Battery voltage (offset 0x1108 - 0x1101 = 7)
|
||||
Status.BatteryDischargeCurrent = regs[8]; // 0x1109: Battery current (offset 8) -- signed value
|
||||
@ -103,7 +97,7 @@ public sealed class FelicitySolarInverter
|
||||
return settings;
|
||||
}
|
||||
|
||||
internal void SetSetting(Setting setting, float value)
|
||||
internal void SetSetting(Setting setting, double value)
|
||||
{
|
||||
ushort registerAddress;
|
||||
|
||||
@ -154,7 +148,23 @@ public sealed class FelicitySolarInverter
|
||||
throw new ArgumentException("Invalid setting!");
|
||||
}
|
||||
|
||||
WriteSingleRegister(registerAddress, (ushort)value);
|
||||
var settingValue = (ushort)value;
|
||||
|
||||
// Build request frame:
|
||||
// [Slave Address][Function Code 0x06][Register Address Hi][Register Address Lo]
|
||||
// [Value Hi][Value Lo][CRC Lo][CRC Hi]
|
||||
var frame = new byte[8];
|
||||
frame[0] = SlaveAddress;
|
||||
frame[1] = 0x06;
|
||||
frame[2] = (byte)(registerAddress >> 8);
|
||||
frame[3] = (byte)(registerAddress & 0xFF);
|
||||
frame[4] = (byte)(settingValue >> 8);
|
||||
frame[5] = (byte)(settingValue & 0xFF);
|
||||
var crc = CalculateCrc(frame, 6);
|
||||
frame[6] = (byte)(crc & 0xFF);
|
||||
frame[7] = (byte)(crc >> 8);
|
||||
|
||||
SendModbusRequest(frame);
|
||||
}
|
||||
|
||||
internal void Close()
|
||||
@ -212,25 +222,6 @@ public sealed class FelicitySolarInverter
|
||||
return registers;
|
||||
}
|
||||
|
||||
static void WriteSingleRegister(ushort registerAddress, ushort value)
|
||||
{
|
||||
// Build request frame:
|
||||
// [Slave Address][Function Code 0x06][Register Address Hi][Register Address Lo]
|
||||
// [Value Hi][Value Lo][CRC Lo][CRC Hi]
|
||||
var frame = new byte[8];
|
||||
frame[0] = SlaveAddress;
|
||||
frame[1] = 0x06;
|
||||
frame[2] = (byte)(registerAddress >> 8);
|
||||
frame[3] = (byte)(registerAddress & 0xFF);
|
||||
frame[4] = (byte)(value >> 8);
|
||||
frame[5] = (byte)(value & 0xFF);
|
||||
var crc = CalculateCrc(frame, 6);
|
||||
frame[6] = (byte)(crc & 0xFF);
|
||||
frame[7] = (byte)(crc >> 8);
|
||||
|
||||
SendModbusRequest(frame);
|
||||
}
|
||||
|
||||
static readonly object _lock = new();
|
||||
|
||||
static byte[] SendModbusRequest(byte[] request)
|
||||
|
||||
@ -3,16 +3,35 @@ using InverterMon.Server.Persistence.Settings;
|
||||
|
||||
namespace InverterMon.Server.InverterService;
|
||||
|
||||
class StatusRetriever(Database db, FelicitySolarInverter inverter, UserSettings userSettings) : BackgroundService
|
||||
class StatusRetriever(Database db, FelicitySolarInverter inverter, UserSettings userSettings, IConfiguration config, ILogger<StatusRetriever> log)
|
||||
: BackgroundService
|
||||
{
|
||||
protected override async Task ExecuteAsync(CancellationToken c)
|
||||
{
|
||||
var port = config["LaunchSettings:DeviceAddress"] ?? throw new ArgumentException("Device address not specified in appsettings.json file!");
|
||||
|
||||
while (!inverter.Connect(port))
|
||||
{
|
||||
log.LogCritical("Unable to connect to the inverter at [{port}]. Retrying in 5 seconds...", port);
|
||||
await Task.Delay(5000);
|
||||
}
|
||||
|
||||
while (!c.IsCancellationRequested)
|
||||
{
|
||||
inverter.Status.BatteryCapacity = userSettings.BatteryCapacity;
|
||||
inverter.Status.PV_MaxCapacity = userSettings.PV_MaxCapacity;
|
||||
|
||||
//todo: get data from inverter and map to CurrentStatus.Result
|
||||
try
|
||||
{
|
||||
inverter.UpdateStatus();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.LogError("Error while reading inverter status data! Details: [{msg}]", e.Message);
|
||||
await Task.Delay(2000);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
db.UpdateTodaysPvGeneration(c);
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ bld.WebHost.ConfigureKestrel(o => o.Listen(IPAddress.Any, port));
|
||||
bld.Services
|
||||
.AddSingleton<UserSettings>()
|
||||
.AddSingleton<Database>()
|
||||
.AddSingleton<FelicitySolarInverter>()
|
||||
.AddSingleton<JkBms>();
|
||||
|
||||
if (!bld.Environment.IsDevelopment())
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
public static class ChargePriority
|
||||
{
|
||||
public const string SolarFirst = "1";
|
||||
public const string SolarAndUtility = "2";
|
||||
public const string OnlySolar = "3";
|
||||
public const string UtilityFirst = "0";
|
||||
public const byte SolarFirst = 1;
|
||||
public const byte SolarAndUtility = 2;
|
||||
public const byte OnlySolar = 3;
|
||||
public const byte UtilityFirst = 0;
|
||||
}
|
||||
@ -2,39 +2,56 @@
|
||||
|
||||
public class CurrentSettings
|
||||
{
|
||||
public string ChargePriority { get; set; } = "000";
|
||||
public string OutputPriority { get; set; } = "000";
|
||||
public string MaxACChargeCurrent { get; set; } = "000";
|
||||
public string MaxCombinedChargeCurrent { get; set; } = "000";
|
||||
public byte ChargePriority { get; set; }
|
||||
public byte OutputPriority { get; set; }
|
||||
public byte MaxACChargeCurrent { get; set; }
|
||||
public byte MaxCombinedChargeCurrent { get; set; }
|
||||
|
||||
decimal _backToGrid;
|
||||
public decimal BackToGridVoltage { get => _backToGrid; set => _backToGrid = RoundToHalfPoints(value); }
|
||||
double _backToGrid;
|
||||
|
||||
decimal _dischargeCuttOff;
|
||||
public decimal DischargeCuttOffVoltage { get => _dischargeCuttOff; set => _dischargeCuttOff = RoundToOneDecimalPoint(value); }
|
||||
public double BackToGridVoltage
|
||||
{
|
||||
get => _backToGrid;
|
||||
set => _backToGrid = value; //RoundToHalfPoints(value);
|
||||
}
|
||||
|
||||
decimal _bulkVoltage;
|
||||
public decimal BulkChargeVoltage
|
||||
double _dischargeCuttOff;
|
||||
|
||||
public double DischargeCuttOffVoltage
|
||||
{
|
||||
get => _dischargeCuttOff;
|
||||
set => _dischargeCuttOff = value; // RoundToOneDecimalPoint(value);
|
||||
}
|
||||
|
||||
double _bulkVoltage;
|
||||
|
||||
public double BulkChargeVoltage
|
||||
{
|
||||
get => _bulkVoltage;
|
||||
set => _bulkVoltage = RoundToOneDecimalPoint(value < _floatVoltage ? _floatVoltage : value);
|
||||
set => _bulkVoltage = value; // RoundToOneDecimalPoint(value < _floatVoltage ? _floatVoltage : value);
|
||||
}
|
||||
|
||||
decimal _floatVoltage;
|
||||
public decimal FloatChargeVoltage
|
||||
double _floatVoltage;
|
||||
|
||||
public double FloatChargeVoltage
|
||||
{
|
||||
get => _floatVoltage;
|
||||
set => _floatVoltage = RoundToOneDecimalPoint(value > _bulkVoltage ? _bulkVoltage : value);
|
||||
set => _floatVoltage = value; // RoundToOneDecimalPoint(value > _bulkVoltage ? _bulkVoltage : value);
|
||||
}
|
||||
|
||||
decimal _backToBattery;
|
||||
public decimal BackToBatteryVoltage { get => _backToBattery; set => _backToBattery = RoundToHalfPoints(value); }
|
||||
double _backToBattery;
|
||||
|
||||
public double BackToBatteryVoltage
|
||||
{
|
||||
get => _backToBattery;
|
||||
set => _backToBattery = value; //RoundToHalfPoints(value);
|
||||
}
|
||||
|
||||
public SystemSpec SystemSpec { get; set; } = new();
|
||||
|
||||
static decimal RoundToHalfPoints(decimal value)
|
||||
=> Math.Round(value * 2, MidpointRounding.AwayFromZero) / 2;
|
||||
// static double RoundToHalfPoints(double value)
|
||||
// => Math.Round(value * 2, MidpointRounding.AwayFromZero) / 2;
|
||||
|
||||
static decimal RoundToOneDecimalPoint(decimal value)
|
||||
=> Math.Round(value, 1, MidpointRounding.AwayFromZero);
|
||||
}
|
||||
// static double RoundToOneDecimalPoint(double value)
|
||||
// => Math.Round(value, 1, MidpointRounding.AwayFromZero);
|
||||
}
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
public static class OutputPriority
|
||||
{
|
||||
public const string SolarFirst = "1";
|
||||
public const string SolarBatteryUtility = "2";
|
||||
public const string UtilityFirst = "0";
|
||||
public const byte SolarFirst = 1;
|
||||
public const byte SolarBatteryUtility = 2;
|
||||
public const byte UtilityFirst = 0;
|
||||
}
|
||||
@ -2,6 +2,6 @@
|
||||
|
||||
public class SetSetting
|
||||
{
|
||||
public string Command { get; set; }
|
||||
public string Value { get; set; }
|
||||
public Setting Setting { get; set; }
|
||||
public double Value { get; set; }
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user