Merge branch 'main' of 91.92.155.224:Innovenergy/Innovenergy_trunk

This commit is contained in:
Yinyin Liu 2026-02-03 11:10:28 +01:00
commit 5f1bcdb0c1
22 changed files with 1062 additions and 1147 deletions

View File

@ -6,11 +6,10 @@ namespace InnovEnergy.App.GrowattCommunication.DataTypes;
public class Configuration
{
public Double MinimumSoC { get; set; }
public Double GridSetPoint { get; set; }
public Double MaximumDischargingCurrent { get; set; }
public Double MaximumChargingCurrent { get; set; }
public EssMode OperatingPriority { get; set; }
public required Int16 BatteriesCount { get; set; }
public Int16 BatteriesCount { get; set; }
}

View File

@ -5,6 +5,6 @@ namespace InnovEnergy.App.GrowattCommunication.ESS;
public record StatusRecord
{
public required WITGrowatRecord AcDcGrowatt { get; set; }
public required WITGrowatRecord InverterRecord { get; set; }
public required Config Config { get; set; }
}

View File

@ -67,8 +67,8 @@ public static class MiddlewareAgent
if (config != null)
{
Console.WriteLine($"Received a configuration message: GridSetPoint is " + config.GridSetPoint +
", MinimumSoC is " + config.MinimumSoC + " and operating priorty is " +config.OperatingPriority + "Number of batteries is " + config.BatteriesCount );
Console.WriteLine($"Received a configuration message: " +
"MinimumSoC is " + config.MinimumSoC + " and operating priorty is " +config.OperatingPriority + "Number of batteries is " + config.BatteriesCount + config.MaximumChargingCurrent + config.MaximumDischargingCurrent);
// Send the reply to the sender's endpoint
_udpListener.Send(replyData, replyData.Length, serverEndpoint);

View File

@ -96,7 +96,7 @@ public static class Program
return new StatusRecord
{
AcDcGrowatt = growattRecord,
InverterRecord = growattRecord,
Config = config // load from disk every iteration, so config can be changed while running
};
}
@ -129,42 +129,39 @@ public static class Program
SendSalimaxStateAlarm(GetSodiHomeStateAlarm(statusrecord),statusrecord);
//await DataLogging(statusrecord, timestamp); // save a csv file locally
//await SaveModbusTcpFile(statusrecord); // save the JSON file for modbuscTCP
Debug.Assert(statusrecord != null, nameof(statusrecord) + " != null");
statusrecord.AcDcGrowatt.RemotePowerControl.WriteLine(" = RemotePowerControl");
statusrecord.AcDcGrowatt.EnableEmsCommunicationFailureTime.WriteLine(" = EnableEmsCommunicationFailureTime");
statusrecord.InverterRecord.RemotePowerControl.WriteLine(" = RemotePowerControl");
statusrecord.InverterRecord.EnableEmsCommunicationFailureTime.WriteLine(" = EnableEmsCommunicationFailureTime");
statusrecord.AcDcGrowatt.EnableCommand.WriteLine(" = EnableCommand");
statusrecord.AcDcGrowatt.ControlPermession.WriteLine(" = ControlPermession");
statusrecord.AcDcGrowatt.MeterPower.WriteLine(" MeterPower");
statusrecord.AcDcGrowatt.ConsumptionPower.WriteLine(" ConsumptionPower");
statusrecord.AcDcGrowatt.ExportedPowerToGridMeter.WriteLine(" ExportedPowerToGrid");
statusrecord.AcDcGrowatt.ImportedPowerFromGrid.WriteLine(" ImportedPowerFromGrid");
statusrecord.AcDcGrowatt.InverterActivePower.WriteLine(" InverterActivePower");
statusrecord.AcDcGrowatt.BatteryChargeCutoffVoltage.WriteLine(" BatteryChargeCutoffVoltage "); //30409 we set power here
statusrecord.AcDcGrowatt.BatteryDischargeCutoffVoltage.WriteLine(" BatteryDishargeCutoffVoltage "); //30409 we set power here
statusrecord.AcDcGrowatt.PowerFactor.WriteLine(" = PowerFactor");
statusrecord.AcDcGrowatt.Batteries[0].Soc.WriteLine(" SOC");
statusrecord.AcDcGrowatt.Batteries[0].Power.WriteLine(" Battery Power");
statusrecord.AcDcGrowatt.Batteries[0].Current.WriteLine(" Battery Current");
statusrecord.AcDcGrowatt.Batteries[0].Voltage.WriteLine(" Battery Voltage");
statusrecord.AcDcGrowatt.BatteryMaxChargeCurrent.WriteLine(" BatteryMaxChargeCurrent "); //30409 we set power here
statusrecord.AcDcGrowatt.BatteryMaxdischargeCurrent.WriteLine(" BatteryMaxDischargeCurrent "); //30409 we set power here
statusrecord.AcDcGrowatt.DischargeCutoffSoc.WriteLine(" DischargeCutoffSoc "); //30409 we set power here
statusrecord.AcDcGrowatt.ChargeCutoffSoc.WriteLine(" ChargeCutoffSoc "); //30409 we set power here
statusrecord.InverterRecord.EnableCommand.WriteLine(" = EnableCommand");
statusrecord.InverterRecord.ControlPermession.WriteLine(" = ControlPermession");
statusrecord.InverterRecord.GridPower.WriteLine(" MeterPower");
statusrecord.InverterRecord.ConsumptionPower.WriteLine(" ConsumptionPower");
statusrecord.InverterRecord.ExportedPowerToGridMeter.WriteLine(" ExportedPowerToGrid");
statusrecord.InverterRecord.ImportedPowerFromGrid.WriteLine(" ImportedPowerFromGrid");
statusrecord.InverterRecord.InverterActivePower.WriteLine(" InverterActivePower");
statusrecord.InverterRecord.MaxSoc.WriteLine(" BatteryChargeCutoffVoltage "); //30409 we set power here
statusrecord.InverterRecord.MinSoc.WriteLine(" BatteryDishargeCutoffVoltage "); //30409 we set power here
statusrecord.InverterRecord.PowerFactor.WriteLine(" = PowerFactor");
statusrecord.InverterRecord.Battery1Soc.WriteLine(" SOC");
statusrecord.InverterRecord.Battery1Power.WriteLine(" Battery Power");
statusrecord.InverterRecord.Battery1Current.WriteLine(" Battery Current");
statusrecord.InverterRecord.Battery1Voltage.WriteLine(" Battery Voltage");
statusrecord.InverterRecord.BatteryMaxChargingCurrent.WriteLine(" BatteryMaxChargeCurrent "); //30409 we set power here
statusrecord.InverterRecord.BatteryMaxDischargingCurrent.WriteLine(" BatteryMaxDischargeCurrent "); //30409 we set power here
statusrecord.InverterRecord.MinSoc.WriteLine(" MinSoc "); //30409 we set power here
statusrecord.InverterRecord.ChargeCutoffSocVoltage.WriteLine(" ChargeCutoffSoc "); //30409 we set power here
statusrecord.AcDcGrowatt.TotalPvPower.WriteLine(" Pv Power "); //30409 we set power here
statusrecord.InverterRecord.PvPower.WriteLine(" Pv Power "); //30409 we set power here
statusrecord.AcDcGrowatt.SystemOperatingMode.WriteLine(" = SystemOperatingMode");
statusrecord.AcDcGrowatt.BatteryOperatingMode.WriteLine(" = BatteryOperatingMode");
statusrecord.AcDcGrowatt.OperatingPriority.WriteLine(" = OperatingPriority"); // 30408 this the duration
statusrecord.InverterRecord.SystemOperatingMode.WriteLine(" = SystemOperatingMode");
statusrecord.InverterRecord.BatteryOperatingMode.WriteLine(" = BatteryOperatingMode");
statusrecord.InverterRecord.OperatingMode.WriteLine(" = OperatingPriority"); // 30408 this the duration
statusrecord.AcDcGrowatt.FaultMainCode.WriteLine(" = FaultMainCode"); // 30408 this the duration
statusrecord.AcDcGrowatt.FaultSubCode.WriteLine(" = FaultSubCode"); // 30408 this the duration
statusrecord.AcDcGrowatt.WarningMainCode.WriteLine(" = WarningMainCode"); // 30408 this the duration
statusrecord.AcDcGrowatt.WarningSubCode.WriteLine(" = WarningSubCode"); // 30408 this the duration
statusrecord.InverterRecord.FaultMainCode.WriteLine(" = FaultMainCode"); // 30408 this the duration
statusrecord.InverterRecord.FaultSubCode.WriteLine(" = FaultSubCode"); // 30408 this the duration
statusrecord.InverterRecord.WarningMainCode.WriteLine(" = WarningMainCode"); // 30408 this the duration
statusrecord.InverterRecord.WarningSubCode.WriteLine(" = WarningSubCode"); // 30408 this the duration
@ -173,10 +170,13 @@ public static class Program
statusrecord.ApplyDefaultSettings();
Console.WriteLine( " ************************************ We are writing ************************************");
if (statusrecord != null)
{
statusrecord.Config.Save(); // save the config file
growattDeviceT415K.Write(statusrecord.AcDcGrowatt);
var stopTime = DateTime.Now;
Console.WriteLine(stopTime.ToString("HH:mm:ss.fff"));
growattDeviceT415K.Write(statusrecord.InverterRecord);
Console.WriteLine(DateTime.Now.ToString("HH:mm:ss.fff"));
}
return statusrecord;
}
catch (Exception e)
@ -185,7 +185,6 @@ public static class Program
Console.WriteLine(e );
return null;
}
}
}
@ -195,7 +194,6 @@ public static class Program
if (status == null) return;
status.Config.MinSoc = config.MinimumSoC;
status.Config.GridSetPoint = config.GridSetPoint * 1000; // converted from kW to W
status.Config.MaximumChargingCurrent = config.MaximumChargingCurrent;
status.Config.MaximumDischargingCurrent = config.MaximumDischargingCurrent;
status.Config.OperatingPriority = config.OperatingPriority;
@ -211,23 +209,23 @@ public static class Program
case EssMode.Off:
return "no mode";
case EssMode.GridPriority:
statusrecord.AcDcGrowatt.RemotePowerControl = true;
statusrecord.AcDcGrowatt.RemotePowerControlChargeDuration = 0; // 30408 this the duration
statusrecord.InverterRecord.RemotePowerControl = true;
statusrecord.InverterRecord.RemotePowerControlChargeDuration = 0; // 30408 this the duration
//statusrecord.AcDcGrowatt.ActivePowerPercent = 50; // 30408 this the duration
//statusrecord.AcDcGrowatt.ActivePowerPercentDerating = 50; // 30408 this the duration
statusrecord.AcDcGrowatt.RemoteChargDischargePower = - 100; //30409 we set power here // for grid priority from 0 to -100
statusrecord.AcDcGrowatt.ActualChargeDischargePowerControlValue.WriteLine(" register 30474");; // this to check what was set
statusrecord.InverterRecord.RemoteChargDischargePower = - 100; //30409 we set power here // for grid priority from 0 to -100
statusrecord.InverterRecord.ActualChargeDischargePowerControlValue.WriteLine(" register 30474");; // this to check what was set
return "Grid priority mode active";
case EssMode.BatteryPriority:
statusrecord.AcDcGrowatt.RemotePowerControl = true;
statusrecord.AcDcGrowatt.RemotePowerControlChargeDuration = 0; // 30408 this the duration
statusrecord.InverterRecord.RemotePowerControl = true;
statusrecord.InverterRecord.RemotePowerControlChargeDuration = 0; // 30408 this the duration
statusrecord.AcDcGrowatt.RemoteChargDischargePower = 100; //30409 we set power here // for battery priority from 0 to 100
statusrecord.AcDcGrowatt.ActualChargeDischargePowerControlValue.WriteLine(" register 30474");; // this to check what was set
statusrecord.InverterRecord.RemoteChargDischargePower = 100; //30409 we set power here // for battery priority from 0 to 100
statusrecord.InverterRecord.ActualChargeDischargePowerControlValue.WriteLine(" register 30474");; // this to check what was set
return "Battery priority mode active";
case EssMode.LoadPriority:
statusrecord.AcDcGrowatt.RemotePowerControl = false;
statusrecord.InverterRecord.RemotePowerControl = false;
return "Load priority mode active";
default:
throw new ArgumentOutOfRangeException(nameof(mode), mode, null);
@ -241,27 +239,27 @@ public static class Program
var alarmList = new List<AlarmOrWarning>();
var warningList = new List<AlarmOrWarning>();
if (record.AcDcGrowatt.SystemOperatingMode == GrowattSystemStatus.Fault)
if (record.InverterRecord.SystemOperatingMode == GrowattSystemStatus.Fault)
{
if (record.AcDcGrowatt.FaultMainCode != 0)
if (record.InverterRecord.FaultMainCode != 0)
{
alarmList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "Growatt Inverter",
Description = record.AcDcGrowatt.WarningMainCode.ToString(), // to add the sub code
Description = record.InverterRecord.WarningMainCode.ToString(), // to add the sub code
});
}
if (record.AcDcGrowatt.WarningMainCode != 0)
if (record.InverterRecord.WarningMainCode != 0)
{
warningList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "Growatt inverter",
Description = record.AcDcGrowatt.FaultMainCode.ToString(), //to add the sub code
Description = record.InverterRecord.FaultMainCode.ToString(), //to add the sub code
});
}
}
@ -330,18 +328,19 @@ public static class Program
if (st is null)
return;
st.AcDcGrowatt.BatteryMaxChargeCurrent = st.Config.MaximumChargingCurrent;
st.AcDcGrowatt.BatteryMaxdischargeCurrent = st.Config.MaximumDischargingCurrent ;
st.AcDcGrowatt.DischargeCutoffSoc = st.Config.MinSoc;
st.AcDcGrowatt.EmsCommunicationFailureTime = 20; // 20 sec
st.AcDcGrowatt.EnableEmsCommunicationFailureTime = false;
st.AcDcGrowatt.EnableCommand = true;
st.AcDcGrowatt.ControlPermession = true;
st.AcDcGrowatt.BatteryChargeCutoffVoltage = 60; //st.Config.BatteryChargeCutoffVoltage;
st.AcDcGrowatt.BatteryDischargeCutoffVoltage = 25; //st.Config.BatteryDischargeCutoffVoltage;
st.InverterRecord.BatteryMaxChargingCurrent = st.Config.MaximumChargingCurrent;
st.InverterRecord.BatteryMaxDischargingCurrent = st.Config.MaximumDischargingCurrent;
st.InverterRecord.MinSoc = (UInt16)st.Config.MinSoc;
st.InverterRecord.EmsCommunicationFailureTime = 20; // 20 sec
st.InverterRecord.EnableEmsCommunicationFailureTime = false;
st.InverterRecord.EnableCommand = true;
st.InverterRecord.ControlPermession = true;
st.InverterRecord.MaxSoc = 60; //st.Config.BatteryChargeCutoffVoltage;
st.InverterRecord.MinSoc = 25; //st.Config.BatteryDischargeCutoffVoltage;
}
private static Dictionary<String, UInt16> ConvertToModbusRegisters(Object value, String outputType, Int32 startingAddress)
private static Dictionary<String, UInt16> ConvertToModbusRegisters(Object value, String outputType,
Int32 startingAddress)
{
var registers = new Dictionary<String, UInt16>();
@ -381,31 +380,33 @@ public static class Program
var modbusData = new Dictionary<String, UInt16>();
// SYSTEM DATA
var result1 = ConvertToModbusRegisters((status.Config.ModbusProtcolNumber * 10), "UInt16", 30001); // this to be updated to modbusTCP version
var result2 = ConvertToModbusRegisters(status.AcDcGrowatt.SystemDateTime.ToUnixTime(), "UInt32", 30002);
var result3 = ConvertToModbusRegisters(status.AcDcGrowatt.SystemOperatingMode, "UInt16", 30004);
var result17 = ConvertToModbusRegisters(status.AcDcGrowatt.OperatingPriority, "UInt16", 30005);
var result1 =
ConvertToModbusRegisters((status.Config.ModbusProtcolNumber * 10), "UInt16",
30001); // this to be updated to modbusTCP version
var result2 = ConvertToModbusRegisters(status.InverterRecord.SystemDateTime.ToUnixTime(), "UInt32", 30002);
var result3 = ConvertToModbusRegisters(status.InverterRecord.SystemOperatingMode, "UInt16", 30004);
var result17 = ConvertToModbusRegisters(status.InverterRecord.OperatingMode, "UInt16", 30005);
// BATTERY SUMMARY (assuming single battery [0]) // this to be improved
var battery = status.AcDcGrowatt.BatteriesRecords!.Batteries[0];
var result4 = ConvertToModbusRegisters((status.Config.BatteriesCount), "UInt16", 31000);
var result8 = ConvertToModbusRegisters((status.AcDcGrowatt.BatteryOperatingMode), "UInt16", 31001);
var result12 = ConvertToModbusRegisters((battery.Voltage.Value * 10), "Int16", 31002);
var result13 = ConvertToModbusRegisters((battery.Current.Value * 10), "Int32", 31003);
var result14 = ConvertToModbusRegisters((battery.Soc.Value * 100), "UInt16", 31005);
var result5 = ConvertToModbusRegisters((battery.Power.Value * 10), "Int32", 31006);
var result8 = ConvertToModbusRegisters((status.InverterRecord.BatteryOperatingMode), "UInt16", 31001);
var result12 = ConvertToModbusRegisters((status.InverterRecord.Battery1Voltage.Value * 10), "Int16", 31002);
var result13 = ConvertToModbusRegisters((status.InverterRecord.Battery1Current.Value * 10), "Int32", 31003);
var result14 = ConvertToModbusRegisters((status.InverterRecord.Battery1Soc.Value * 100), "UInt16", 31005);
var result5 = ConvertToModbusRegisters((status.InverterRecord.Battery1Power.Value * 10), "Int32", 31006);
var result7 = ConvertToModbusRegisters((status.AcDcGrowatt.DischargeCutoffSoc * 100), "UInt16", 31008);
var result20 = ConvertToModbusRegisters((status.AcDcGrowatt.ChargeCutoffSoc * 100), "UInt16", 31009);
var result15 = ConvertToModbusRegisters((status.AcDcGrowatt.BatteriesRecords!.AverageSoh * 100), "UInt16", 310010);
var result16 = ConvertToModbusRegisters((battery.BatteryAmbientTemperature.Value * 100), "UInt16", 31011);
var result21 = ConvertToModbusRegisters((status.AcDcGrowatt.BatteryMaxChargeCurrent * 10), "UInt16", 31012);
var result22 = ConvertToModbusRegisters((status.AcDcGrowatt.BatteryMaxdischargeCurrent * 10), "UInt16", 31013);
var result23 = ConvertToModbusRegisters((status.AcDcGrowatt.BatteryChargeCutoffVoltage * 10), "UInt16", 31014);
var result7 = ConvertToModbusRegisters((status.InverterRecord.MinSoc * 100), "UInt16", 31008);
var result20 = ConvertToModbusRegisters((status.InverterRecord.ChargeCutoffSocVoltage * 100), "UInt16", 31009);
var result15 =
ConvertToModbusRegisters((status.InverterRecord.Battery1Soh * 100), "UInt16", 310010);
var result16 = ConvertToModbusRegisters((status.InverterRecord.Battery1AmbientTemperature.Value * 100), "UInt16", 31011);
var result21 = ConvertToModbusRegisters((status.InverterRecord.BatteryMaxChargingCurrent * 10), "UInt16", 31012);
var result22 = ConvertToModbusRegisters((status.InverterRecord.BatteryMaxDischargingCurrent * 10), "UInt16", 31013);
var result23 = ConvertToModbusRegisters((status.InverterRecord.MaxSoc * 10), "UInt16", 31014);
var result18 = ConvertToModbusRegisters((status.AcDcGrowatt.TotalPvPower.Value * 10), "UInt32", 32000);
var result19 = ConvertToModbusRegisters((status.AcDcGrowatt.MeterPower * 10), "Int32", 33000);
var result18 = ConvertToModbusRegisters((status.InverterRecord.PvPower.Value * 10), "UInt32", 32000);
var result19 = ConvertToModbusRegisters((status.InverterRecord.GridPower * 10), "Int32", 33000);
// Merge all results into one dictionary
@ -584,7 +585,8 @@ public static class Program
uploadSucceeded = true;
Console.WriteLine("✅ File uploaded to S3 successfully.");
Console.WriteLine("---------------------------------------- Resending FailedUploadedFiles----------------------------------------");
Console.WriteLine(
"---------------------------------------- Resending FailedUploadedFiles----------------------------------------");
Heartbit();
await ResendLocalFailedFilesAsync(s3Config); // retry any pending failed files

View File

@ -142,9 +142,9 @@ public static class Aggregator
{
batterySoc.Add((double)jsonObject["Battery"]["Soc"]);
}
if (jsonObject["PvOnDc"] != null && jsonObject["PvOnDc"]["DcWh"] != null)
if (jsonObject["PvOnDc"] != null && jsonObject["PvOnDc"]["1"]["DcWh"] != null) // todo update to all pv
{
pvPowerSum.Add((double)jsonObject["PvOnDc"]["DcWh"]);
pvPowerSum.Add((double)jsonObject["PvOnDc"]["1"]["DcWh"]);
}
if (jsonObject["Battery"] != null && jsonObject["Battery"]["Dc"]["Power"] != null)
{
@ -316,7 +316,7 @@ public static class Aggregator
ChargingBatteryPower = batteryChargePower.Any() ? batteryChargePower.Average() : 0.0,
GridExportPower = gridPowerExport.Any() ? gridPowerExport.Sum() : 0.0,
GridImportPower = gridPowerImport.Any() ? gridPowerImport.Sum() : 0.0,
PvPower = pvPower.Any() ? pvPower.Last() : 0.0,
PvPower = pvPower.Any() ? pvPower.Max() : 0.0,
HeatingPower = heatingPowerAvg.Any() ? heatingPowerAvg.Average() : 0.0,
};

View File

@ -1,12 +1,13 @@
using InnovEnergy.Lib.Devices.Sinexcel_12K_TL.DataType;
namespace InnovEnergy.App.SinexcelCommunication.DataTypes;
public class Configuration
{
public Double MinimumSoC { get; set; }
public Double GridSetPoint { get; set; }
// public Double MaximumDischargingCurrent { get; set; }
// public Double MaximumChargingCurrent { get; set; }
// public EssMode OperatingPriority { get; set; }
// public required Int16 BatteriesCount { get; set; }
public Double MaximumDischargingCurrent { get; set; }
public Double MaximumChargingCurrent { get; set; }
public WorkingMode OperatingPriority { get; set; }
public Int16 BatteriesCount { get; set; }
}

View File

@ -1,8 +0,0 @@
namespace InnovEnergy.App.SinexcelCommunication;
public enum DeviceState
{
Disabled,
Measured,
Computed
}

View File

@ -5,6 +5,6 @@ namespace InnovEnergy.App.SinexcelCommunication.ESS;
public record StatusRecord
{
public required SinexcelRecord SinexcelRecord { get; set; }
public required SinexcelRecord InverterRecord { get; set; }
public required Config Config { get; set; }
}

View File

@ -67,8 +67,8 @@ public static class MiddlewareAgent
if (config != null)
{
Console.WriteLine($"Received a configuration message: GridSetPoint is " + config.GridSetPoint +
", MinimumSoC is " + config.MinimumSoC + " and operating priorty is " );
Console.WriteLine($"Received a configuration message: " +
"MinimumSoC is " + config.MinimumSoC + " and operating priorty is " +config.OperatingPriority + "Number of batteries is " + config.BatteriesCount + config.MaximumChargingCurrent + config.MaximumDischargingCurrent);
// Send the reply to the sender's endpoint
_udpListener.Send(replyData, replyData.Length, serverEndpoint);

View File

@ -24,6 +24,8 @@ using Formatting = Newtonsoft.Json.Formatting;
using JsonSerializer = System.Text.Json.JsonSerializer;
using static InnovEnergy.App.SinexcelCommunication.MiddlewareClasses.MiddlewareAgent;
using System.Diagnostics.CodeAnalysis;
using InnovEnergy.Lib.Devices.Sinexcel_12K_TL.DataType;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
namespace InnovEnergy.App.SinexcelCommunication;
@ -31,7 +33,7 @@ namespace InnovEnergy.App.SinexcelCommunication;
[SuppressMessage("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic access otherwise can break functionality when trimming application code")]
internal static class Program
{
private static readonly TimeSpan UpdateInterval = TimeSpan.FromSeconds(4);
private static readonly TimeSpan UpdateInterval = TimeSpan.FromSeconds(5);
private const UInt16 NbrOfFileToConcatenate = 15; // add this to config file
private static UInt16 _fileCounter = 0;
private static Channel _sinexcelChannel;
@ -54,7 +56,7 @@ internal static class Program
public static async Task Main(String[] args)
{
_sinexcelChannel = new SerialPortChannel(Port, BaudRate, Parity, DataBits, StopBits);
InitializeCommunicationToMiddleware();
while (true)
{
try
@ -85,7 +87,7 @@ internal static class Program
return new StatusRecord
{
SinexcelRecord = sinexcelRecord,
InverterRecord = sinexcelRecord,
Config = config // load from disk every iteration, so config can be changed while running
};
}
@ -111,61 +113,57 @@ internal static class Program
var startTime = DateTime.Now;
Console.WriteLine("***************************** Reading Battery Data *********************************************");
Console.WriteLine(startTime.ToString("HH:mm:ss.fff"));
Console.WriteLine(startTime.ToString("HH:mm:ss.fff ")+ "Start Reading");
// the order matter of the next three lines
var statusrecord = ReadStatus();
if (statusrecord == null)
return null;
statusrecord.SinexcelRecord.GridAPhaseVoltage.WriteLine(" = Grid A PhaseVoltage");
statusrecord.SinexcelRecord.GridBPhaseVoltage.WriteLine(" = Grid B PhaseVoltage");
statusrecord.SinexcelRecord.GridCPhaseVoltage.WriteLine(" = Grid C PhaseVoltage");
// Console.WriteLine( statusrecord.InverterRecord.TimedChargeAndDischargeOff + " TimedChargeAndDischargeOff ");
Console.WriteLine( statusrecord.InverterRecord.Battery1Power + " Battery1Power ");
Console.WriteLine( statusrecord.InverterRecord.Battery1Soc + " Battery1Soc ");
Console.WriteLine( statusrecord.InverterRecord.RepetitiveWeeks + " RepetitiveWeeks ");
Console.WriteLine( statusrecord.InverterRecord.EffectiveStartDate + " EffectiveStartDate ");
Console.WriteLine( statusrecord.InverterRecord.EffectiveEndDate + " EffectiveEndDate ");
Console.WriteLine( statusrecord.InverterRecord.ChargingPowerPeriod1 + " ChargingPowerPeriod1 ");
Console.WriteLine( statusrecord.InverterRecord.ChargeStartTimePeriod1 + " ChargeStartTimePeriod1 ");
Console.WriteLine( statusrecord.InverterRecord.ChargeEndTimePeriod1 + " ChargeEndTimePeriod1 ");
statusrecord.SinexcelRecord.GridAPhaseCurrent.WriteLine(" = Grid A PhaseCurrent");
statusrecord.SinexcelRecord.GridBPhaseCurrent.WriteLine(" = Grid B PhaseCurrent");
statusrecord.SinexcelRecord.GridCPhaseCurrent.WriteLine(" = Grid C PhaseCurrent");
Console.WriteLine( statusrecord.InverterRecord.DischargeStartTimePeriod1 + " DischargeStartTimePeriod1 ");
Console.WriteLine( statusrecord.InverterRecord.DischargeEndTimePeriod1 + " DischargeEndTimePeriod1 ");
Console.WriteLine( statusrecord.InverterRecord.PowerOn + " PowerOn ");
Console.WriteLine( statusrecord.InverterRecord.PowerOff + " PowerOff ");
Console.WriteLine( statusrecord.InverterRecord.WorkingMode + " WorkingMode ");
// Console.WriteLine( statusrecord.InverterRecord.FaultClearing + " FaultClearing ");
SendSalimaxStateAlarm(GetSodiHomeStateAlarm(statusrecord),statusrecord);
statusrecord.SinexcelRecord.GridAPhaseActivePower.WriteLine(" = A Grid Active Power");
statusrecord.SinexcelRecord.GridBPhaseActivePower.WriteLine(" = B Grid Active Power");
statusrecord.SinexcelRecord.GridCPhaseActivePower.WriteLine(" = C Grid Active Power");
statusrecord.SinexcelRecord.GridVoltageFrequency.WriteLine(" = Frequency");
statusrecord.SinexcelRecord.ElectricMeterCPhaseActivePower.WriteLine(" Meter Phase C Power");
statusrecord.SinexcelRecord.ElectricMeterBPhaseActivePower.WriteLine(" Meter Phase B Power");
statusrecord.SinexcelRecord.ElectricMeterAPhaseActivePower.WriteLine(" Meter Phase A Power");
statusrecord.SinexcelRecord.ElectricMeterAPhaseCurrent.WriteLine(" Meter Phase C Current ");
statusrecord.SinexcelRecord.ElectricMeterBPhaseCurrent.WriteLine(" Meter Phase B Current ");
statusrecord.SinexcelRecord.ElectricMeterBPhaseCurrent.WriteLine(" Meter Phase A Current ");
statusrecord.SinexcelRecord.WorkingMode.WriteLine(" workingmode");
statusrecord.SinexcelRecord.BatteryVoltage.WriteLine(" BatteryVoltage");
statusrecord.SinexcelRecord.BatteryVoltage1.WriteLine(" BatteryVoltage1");
statusrecord.SinexcelRecord.BatteryVoltage2.WriteLine(" BatteryVoltage2");
statusrecord.SinexcelRecord.BatteryPower1.WriteLine(" BatteryPower1");
statusrecord.SinexcelRecord.BatteryPower2.WriteLine(" BatteryPower2");
statusrecord.SinexcelRecord.TotalBatteryPower.WriteLine(" TotalBatteryPower");
statusrecord.SinexcelRecord.EnableBattery1.WriteLine(" EnableBattery1");
statusrecord.SinexcelRecord.EnableBattery2.WriteLine(" EnableBattery2");
statusrecord.SinexcelRecord.MaxChargingCurrentBattery1.WriteLine(" MaxChargingCurrentBattery1");
statusrecord.SinexcelRecord.MaxChargingCurrentBattery2.WriteLine(" MaxChargingCurrentBattery2");
statusrecord.SinexcelRecord.MaxDischargingCurrentBattery1.WriteLine(" MaxChargingCurrentBattery1");
statusrecord.SinexcelRecord.MaxDischargingCurrentBattery2.WriteLine(" MaxChargingCurrentBattery2");
//EssModeControl(statusrecord);
// statusrecord.ApplyDefaultSettings();
Console.WriteLine( " ************************************ We are writing ************************************");
var startWritingTime = DateTime.Now;
Console.WriteLine(startWritingTime.ToString("HH:mm:ss.fff ") +"start Writing");
statusrecord?.Config.Save(); // save the config file
//sinexcelDevice.Write(statusrecord?.SinexcelRecord);
if (statusrecord != null)
{
statusrecord.InverterRecord.WorkingMode = WorkingMode.TimeChargeDischarge;
//statusrecord.InverterRecord.TimedChargeAndDischargeOff = 0;
statusrecord.InverterRecord.RepetitiveWeeks = SinexcelWeekDays.All;
statusrecord.InverterRecord.EffectiveStartDate = DateTime.Today.AddDays(-1);
statusrecord.InverterRecord.EffectiveEndDate = DateTime.Today.AddDays(2);
statusrecord.InverterRecord.ChargingPowerPeriod1 = 3;
statusrecord.InverterRecord.DishargingPowerPeriod1 = 3;
statusrecord.InverterRecord.DischargeStartTimePeriod1 = new TimeSpan(16, 00, 0);
statusrecord.InverterRecord.DischargeEndTimePeriod1 = new TimeSpan(17, 03, 0);
statusrecord.InverterRecord.PowerOn = 1;
statusrecord.InverterRecord.PowerOff = 0;
//statusrecord.InverterRecord.FaultClearing = 1;
}
if (statusrecord?.InverterRecord != null) sinexcelDevice.Write(statusrecord.InverterRecord);
var stopTime = DateTime.Now;
Console.WriteLine(stopTime.ToString("HH:mm:ss.fff"));
Console.WriteLine(stopTime.ToString("HH:mm:ss.fff ")+ "run iteration time finish");
return statusrecord;
}
catch (Exception e)
@ -178,6 +176,61 @@ internal static class Program
}
}
private static StatusMessage GetSodiHomeStateAlarm(StatusRecord? record)
{
var s3Bucket = Config.Load().S3?.Bucket;
var alarmList = new List<AlarmOrWarning>();
var warningList = new List<AlarmOrWarning>();
/*
if (record.SinexcelRecord.WorkingMode == GrowattSystemStatus.Fault)
{
if (record.AcDcGrowatt.FaultMainCode != 0)
{
alarmList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "Growatt Inverter",
Description = record.AcDcGrowatt.WarningMainCode.ToString(), // to add the sub code
});
}
if (record.AcDcGrowatt.WarningMainCode != 0)
{
warningList.Add(new AlarmOrWarning
{
Date = DateTime.Now.ToString("yyyy-MM-dd"),
Time = DateTime.Now.ToString("HH:mm:ss"),
CreatedBy = "Growatt inverter",
Description = record.AcDcGrowatt.FaultMainCode.ToString(), //to add the sub code
});
}
}*/
_sodiohomeAlarmState = warningList.Any()
? SodistoreAlarmState.Orange
: SodistoreAlarmState.Green; // this will be replaced by LedState
_sodiohomeAlarmState = alarmList.Any()
? SodistoreAlarmState.Red
: _sodiohomeAlarmState; // this will be replaced by LedState
var installationId = GetInstallationId(s3Bucket ?? string.Empty);
var returnedStatus = new StatusMessage
{
InstallationId = installationId,
Product = 2,
Status = _sodiohomeAlarmState,
Type = MessageType.AlarmOrWarning,
Alarms = alarmList,
Warnings = warningList
};
return returnedStatus;
}
private static Int32 GetInstallationId(String s3Bucket)
{
var part = s3Bucket.Split('-').FirstOrDefault();
@ -220,11 +273,10 @@ internal static class Program
if (status == null) return;
status.Config.MinSoc = config.MinimumSoC;
status.Config.GridSetPoint = config.GridSetPoint * 1000; // converted from kW to W
//status.Config.MaximumChargingCurrent = config.MaximumChargingCurrent;
//status.Config.MaximumDischargingCurrent = config.MaximumDischargingCurrent;
//status.Config.OperatingPriority = config.OperatingPriority;
//status.Config.BatteriesCount = config.BatteriesCount;
status.Config.MaximumChargingCurrent = config.MaximumChargingCurrent;
status.Config.MaximumDischargingCurrent = config.MaximumDischargingCurrent;
status.Config.OperatingPriority = config.OperatingPriority;
status.Config.BatteriesCount = config.BatteriesCount;
}
private static async Task<Boolean> SaveModbusTcpFile(StatusRecord status)
@ -232,10 +284,11 @@ internal static class Program
var modbusData = new Dictionary<String, UInt16>();
// SYSTEM DATA
var result1 = ConvertToModbusRegisters((status.Config.MinSoc * 10), "UInt16", 30001); // this to be updated to modbusTCP version
var result2 = ConvertToModbusRegisters(status.SinexcelRecord.GridAPhaseVoltage, "UInt32", 30002);
var result1 = ConvertToModbusRegisters((status.Config.ModbusProtcolNumber * 10), "UInt16", 30001); // this to be updated to modbusTCP version
var result2 = ConvertToModbusRegisters(status.InverterRecord.SystemDateTime.ToUnixTime(), "UInt32", 30002);
// Merge all results into one dictionary
var allResults = new[]
{
result1,result2
@ -254,43 +307,72 @@ internal static class Program
//Console.WriteLine("JSON file written successfully.");
//Console.WriteLine(json);
var stopTime = DateTime.Now;
Console.WriteLine(stopTime.ToString("HH:mm:ss.fff" )+ " Finish the loop");
return true;
}
private static Dictionary<String, UInt16> ConvertToModbusRegisters(Object value, String outputType, Int32 startingAddress)
private static Dictionary<string, ushort> ConvertToModbusRegisters(object value, string outputType, int startingAddress)
{
var registers = new Dictionary<String, UInt16>();
var regs = new Dictionary<string, ushort>(capacity: 2);
switch (outputType)
{
case "UInt16":
registers[startingAddress.ToString()] = Convert.ToUInt16(value);
{
regs[$"{startingAddress}"] = Convert.ToUInt16(value);
break;
}
case "Int16":
var int16Val = Convert.ToInt16(value);
registers[startingAddress.ToString()] = (UInt16)int16Val; // reinterpret signed as ushort
{
short v = Convert.ToInt16(value);
regs[$"{startingAddress}"] = unchecked((ushort)v); // reinterpret
break;
}
case "UInt32":
var uint32Val = Convert.ToUInt32(value);
registers[startingAddress.ToString()] = (UInt16)(uint32Val & 0xFFFF); // Low word
registers[(startingAddress + 1).ToString()] = (UInt16)(uint32Val >> 16); // High word
{
uint v = Convert.ToUInt32(value);
ushort hi = (ushort)(v >> 16);
ushort lo = (ushort)(v & 0xFFFF);
regs[$"{startingAddress}"] = hi; // HIGH word first (Modbus standard)
regs[$"{startingAddress + 1}"] = lo; // then LOW word
break;
}
case "Int32":
var int32Val = Convert.ToInt32(value);
var raw = unchecked((UInt32)int32Val); // reinterprets signed int as unsigned
registers[startingAddress.ToString()] = (UInt16)(raw & 0xFFFF);
registers[(startingAddress + 1).ToString()] = (UInt16)(raw >> 16);
{
int v = Convert.ToInt32(value);
uint raw = unchecked((uint)v); // bit-reinterpret
ushort hi = (ushort)(raw >> 16);
ushort lo = (ushort)(raw & 0xFFFF);
regs[$"{startingAddress}"] = hi; // HIGH word
regs[$"{startingAddress + 1}"] = lo; // LOW word
break;
}
case "Float": // IEEE-754 single
{
float f = Convert.ToSingle(value);
// Convert to bytes, then to two big-endian 16-bit words
var bytes = BitConverter.GetBytes(f); // little-endian on most platforms
Array.Reverse(bytes); // to big-endian byte order
ushort hi = (ushort)((bytes[0] << 8) | bytes[1]);
ushort lo = (ushort)((bytes[2] << 8) | bytes[3]);
regs[$"{startingAddress}"] = hi;
regs[$"{startingAddress + 1}"] = lo;
break;
}
default:
throw new ArgumentException("Unsupported output type: " + outputType);
throw new ArgumentException($"Unsupported output type: {outputType}");
}
return registers;
return regs;
}
private static async Task<Boolean> DataLogging(StatusRecord status, DateTime timeStamp)
{
var csv = status.ToCsv();

View File

@ -1,13 +0,0 @@
using InnovEnergy.Lib.Utils.Net;
namespace InnovEnergy.App.SinexcelCommunication;
public class SalimaxDevice : Ip4Address
{
public required DeviceState DeviceState { get; init; }
public override String ToString() => $"{base.ToString()} ({DeviceState})";
public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), DeviceState);
}

View File

@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;
using InnovEnergy.Lib.Devices.Sinexcel_12K_TL.DataType;
using InnovEnergy.Lib.Utils;
using static System.Text.Json.JsonSerializer;
@ -17,16 +18,25 @@ public class Config
public required Double MinSoc { get; set; }
public required Double GridSetPoint { get; set; }
public required Double MaximumDischargingCurrent { get; set; }
public required Double MaximumChargingCurrent { get; set; }
public required WorkingMode OperatingPriority { get; set; }
public required Int16 BatteriesCount { get; set; }
public required Double ModbusProtcolNumber { get; set; }
public required S3Config? S3 { get; set; }
private static String? LastSavedData { get; set; }
public static Config Default => new()
{
MinSoc = 20,
GridSetPoint = 0,
MaximumChargingCurrent = 180,
MaximumDischargingCurrent = 180,
OperatingPriority = WorkingMode.TimeChargeDischarge,
BatteriesCount = 0,
ModbusProtcolNumber = 1.2,
S3 = new()
{
Bucket = "1-3e5b3069-214a-43ee-8d85-57d72000c19d",

View File

@ -137,9 +137,9 @@ public static class Aggregator
{
batterySoc.Add((double)jsonObject["Battery"]["Soc"]);
}
if (jsonObject["PvOnDc"] != null && jsonObject["PvOnDc"]["DcWh"] != null)
if (jsonObject["PvOnDc"] != null && jsonObject["PvOnDc"]["1"]["DcWh"] != null) // todo update to all pv
{
pvPowerSum.Add((double)jsonObject["PvOnDc"]["DcWh"]);
pvPowerSum.Add((double)jsonObject["PvOnDc"]["1"]["DcWh"]);
}
if (jsonObject["Battery"] != null && jsonObject["Battery"]["Power"] != null)
{
@ -295,7 +295,7 @@ public static class Aggregator
ChargingBatteryPower = batteryChargePower.Any() ? batteryChargePower.Average() : 0.0,
GridExportPower = gridPowerExport.Any() ? gridPowerExport.Sum() : 0.0,
GridImportPower = gridPowerImport.Any() ? gridPowerImport.Sum() : 0.0,
PvPower = pvPower.Any() ? pvPower.Last() : 0.0,
PvPower = pvPower.Any() ? pvPower.Max() : 0.0,
HeatingPower = heatingPowerAvg.Any() ? heatingPowerAvg.Average() : 0.0,
};

View File

@ -1,272 +0,0 @@
using System.Text;
using Microsoft.AspNetCore.Mvc;
namespace DataCollectorWebApp;
public class LoginResponse
{
public string Token { get; set; }
public object User { get; set; } // or a User class if needed
public bool AccessToSalimax { get; set; }
public bool AccessToSalidomo { get; set; }
public bool AccessToSodiohome { get; set; }
public bool AccessToSodistoreMax { get; set; }
}
public class Installation
{
//Each installation has 2 roles, a read role and a write role.
//There are 2 keys per role a public key and a secret
//Product can be 0 or 1, 0 for Salimax, 1 for Salidomo
public String Name { get; set; }
public String Location { get; set; }
public String Region { get; set; } = "";
public String Country { get; set; } = "";
public String VpnIp { get; set; } = "";
public String InstallationName { get; set; } = "";
public String S3Region { get; set; } = "sos-ch-dk-2";
public String S3Provider { get; set; } = "exo.io";
public String S3WriteKey { get; set; } = "";
public String S3Key { get; set; } = "";
public String S3WriteSecret { get; set; } = "";
public String S3Secret { get; set; } = "";
public int S3BucketId { get; set; } = 0;
public String ReadRoleId { get; set; } = "";
public String WriteRoleId { get; set; } = "";
public Boolean TestingMode { get; set; } = false;
public int Status { get; set; } = -1;
public int Product { get; set; } = 0;
public int Device { get; set; } = 0;
public string SerialNumber { get; set; } = "";
public string InverterSN { get; set; } = "";
public string DataloggerSN { get; set; } = "";
public String OrderNumbers { get; set; }
public String VrmLink { get; set; } = "";
}
[Controller]
public class InstallationsController : Controller
{
[HttpGet]
[Route("/Installations")]
[Produces("text/html")]
public async Task<IActionResult> Index()
{
const string HtmlHeader = @"
<html>
<head>
<title>Inesco Energy Installations Overview</title>
<style>
body {
font-family: sans-serif;
margin: 2rem;
}
table {
border-collapse: collapse;
width: 100%;
font-size: 0.9rem;
}
th, td {
padding: 0.75rem;
border: 1px solid rgb(200, 200, 200);
text-align: left;
}
thead th {
background-color: #f0f0f0;
font-weight: bold;
border-bottom: 2px solid #EB9486;
}
tbody tr:nth-child(odd) {
background-color: #f9f9f9;
}
a {
color: #0645AD;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
.status-circle {
display: inline-block;
width: 15px;
height: 15px;
border-radius: 50%;
margin-left: 50%;
}
.status-0 { background-color: #4CAF50; } /* Green */
.status-1 { background-color: #FF9800; } /* Orange */
.status-2 { background-color: #F44336; } /* Red */
.centered {
text-align: center;
vertical-align: middle;
}
.offline-symbol {
font-size: 1.2rem;
color: #F44336; /* Gray */
display: inline-block;
line-height: 1;
width: 15px;
height: 15px;
border-radius: 50%;
margin-left: 50%;
}
.status-cell {
text-align: center; /* center horizontally */
vertical-align: middle; /* center vertically */
}
</style>
</head>
<body>
<h1>Installation Overview</h1>
<table>
<thead>
<tr>
<th class=""centered"">Name</th>
<th class=""centered"">Product</th>
<th class=""centered"">Location</th>
<th class=""centered"">VPN IP</th>
<th class=""centered"">Status</th>
</tr>
</thead>
<tbody>
";
const string HtmlFooter = @"
</tbody>
</table>
</body>
</html>
";
string GetProductName(int productId)
{
return productId switch
{
0 => "Salimax",
1 => "Salidomo",
2 => "SodioHome",
3 => "SodistoreMax",
};
}
string GetStatusHtml(int status)
{
if (status == -1)
{
return "<span class='offline-symbol' title='Offline'>&times;</span>";
}
var statusClass = $"status-{status}";
var title = status switch
{
0 => "Online",
1 => "Warning",
2 => "Error",
_ => "Unknown"
};
return $"<span class='status-circle {statusClass}' title='{title}'></span>";
}
string BuildRowHtml(Installation i) => $@"
<tr>
<td>{i.Name}</td>
<td>{GetProductName(i.Product)}</td>
<td>{i.Location}</td>
<td>{i.VpnIp}</td>
<td>{GetStatusHtml(i.Status)}</td>
</tr>
";
var installations = await FetchInstallationsFromApi();
var sb = new StringBuilder();
sb.Append(HtmlHeader);
foreach (var i in installations)
{
sb.Append(BuildRowHtml(i));
}
sb.Append(HtmlFooter);
return Content(sb.ToString(), "text/html");
}
public async Task<List<Installation>?> FetchInstallationsFromApi()
{
var username = "baumgartner@innov.energy";
var password = "1234";
using var http = new HttpClient { BaseAddress = new Uri("https://monitor.inesco.energy/api/") };
// Step 1: Login
var loginResponse = await http.PostAsync($"Login?username={username}&password={password}", null);
if (!loginResponse.IsSuccessStatusCode)
{
Console.WriteLine("Login failed with status code {StatusCode}", loginResponse.StatusCode);
return null;
}
var loginData = await loginResponse.Content.ReadFromJsonAsync<LoginResponse>();
if (loginData?.Token is null)
{
Console.WriteLine("Login succeeded but token was missing");
return null;
}
var token = loginData.Token;
Console.WriteLine($"Token: {token}");
var installations = new List<Installation>();
var getInstallationsRequestResponse = await http.GetAsync($"GetAllInstallationsFromProduct?product=0&authToken={token}");
var newInstallations= await getInstallationsRequestResponse.Content.ReadFromJsonAsync<List<Installation>>();
if (newInstallations != null)
{
installations.AddRange(newInstallations);
}
getInstallationsRequestResponse = await http.GetAsync($"GetAllInstallationsFromProduct?product=1&authToken={token}");
newInstallations= await getInstallationsRequestResponse.Content.ReadFromJsonAsync<List<Installation>>();
if (newInstallations != null)
{
installations.AddRange(newInstallations);
}
getInstallationsRequestResponse = await http.GetAsync($"GetAllInstallationsFromProduct?product=2&authToken={token}");
newInstallations= await getInstallationsRequestResponse.Content.ReadFromJsonAsync<List<Installation>>();
if (newInstallations != null)
{
installations.AddRange(newInstallations);
}
getInstallationsRequestResponse = await http.GetAsync($"GetAllInstallationsFromProduct?product=3&authToken={token}");
newInstallations= await getInstallationsRequestResponse.Content.ReadFromJsonAsync<List<Installation>>();
if (newInstallations != null)
{
installations.AddRange(newInstallations);
}
//Console.WriteLine("Installations retrieved ",installations);
return installations;
}
}

View File

@ -1,14 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.OpenApi" Version="1.6.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
</Project>

View File

@ -1,19 +0,0 @@
using Microsoft.AspNetCore.Builder;
namespace InnovEnergy.App.DataCollectorWebApp;
public static class Program
{
public static async Task Main(string[] args)
{
Console.WriteLine("Starting DataCollectorWebApp");
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
await app.RunAsync();
}
}

View File

@ -15,10 +15,10 @@ public partial class WITGrowatRecord
//public BatteriesRecord? BatteriesRecords => BatteriesRecord.FromBatteries(Batteries);
public ActivePower ConsumptionPower => MeterPower + InverterActivePower ;
public ActivePower InverterActivePower => _ActivePower;
public ReactivePower InverterReactivePower => _ReactivePower;
public Frequency Frequency => _Frequency;
public ActivePower ConsumptionPower => GridPower + InverterActivePower ;
public ActivePower InverterActivePower => _activePower;
public ReactivePower InverterReactivePower => _reactivePower;
public Frequency Frequency => _frequency;
public VoltageRms GridAbLineVoltage => _GridAbLineVoltage;
public VoltageRms GridBcLineVoltage => _GridBcLineVoltage;
@ -27,7 +27,7 @@ public partial class WITGrowatRecord
public CurrentRms PhaseBCurrent => _PhaseBCurrent;
public CurrentRms PhaseCCurrent => _PhaseCCurrent;
public ActivePower MeterPower => _importedPowerFromGrid - _exportedPowerToGrid;
public ActivePower GridPower => _importedPowerFromGrid - _exportedPowerToGrid;
public ActivePower ExportedPowerToGridMeter => _exportedPowerToGrid;
public ActivePower ImportedPowerFromGrid => _importedPowerFromGrid;
@ -38,34 +38,33 @@ public partial class WITGrowatRecord
public Energy EnergyToGrid => _EnergyToGrid;
public Energy TotalEnergyToGrid => _TotalEnergyToGrid;
public GrowattSystemStatus SystemOperatingMode => (GrowattSystemStatus)_SystemOperatingMode;
public BatteryoperatinStatus BatteryOperatingMode => (BatteryoperatinStatus) _BatteryOperatingMode;
public OperatingPriority OperatingPriority => (OperatingPriority)_OperatingPriority;
public GrowattSystemStatus SystemOperatingMode => (GrowattSystemStatus)_systemOperatingMode;
public BatteryoperatinStatus BatteryOperatingMode => (BatteryoperatinStatus) _batteryOperatingMode;
public OperatingPriority OperatingMode => (OperatingPriority)_operatingPriority;
public UInt16 FaultMainCode => _FaultMainCode; // need to pre proceesed
public UInt16 FaultSubCode => _FaultSubCode; // need to pre proceesed
public UInt16 WarningMainCode => _WarningMainCode; // need to pre proceesed
public UInt16 WarningSubCode => _WarningSubCode; // need to pre proceesed
public UInt16 FaultMainCode => _faultMainCode; // need to pre proceesed
public UInt16 FaultSubCode => _faultSubCode; // need to pre proceesed
public UInt16 WarningMainCode => _warningMainCode; // need to pre proceesed
public UInt16 WarningSubCode => _warningSubCode; // need to pre proceesed
public Voltage Pv1Voltage => _Pv1Voltage;
public Current Pv1Current => _Pv1Current;
public Voltage Pv2Voltage => _Pv2Voltage;
public Current Pv2Current => _Pv2Current;
public Voltage Pv3Voltage => _Pv3Voltage;
public Current Pv3Current => _Pv3Current;
public Voltage Pv4Voltage => _Pv4Voltage;
public Current Pv4Current => _Pv4Current;
public Voltage Pv5Voltage => _Pv5Voltage;
public Current Pv5Current => _Pv5Current;
public Voltage Pv6Voltage => _Pv6Voltage;
public Current Pv6Current => _Pv6Current;
public Voltage Pv1Voltage => _pv1Voltage;
public Current Pv1Current => _pv1Current;
public Voltage Pv2Voltage => _pv2Voltage;
public Current Pv2Current => _pv2Current;
public Voltage Pv3Voltage => _pv3Voltage;
public Current Pv3Current => _pv3Current;
public Voltage Pv4Voltage => _pv4Voltage;
public Current Pv4Current => _pv4Current;
public Voltage Pv5Voltage => _pv5Voltage;
public Current Pv5Current => _pv5Current;
public Voltage Pv6Voltage => _pv6Voltage;
public Current Pv6Current => _pv6Current;
public DcPower Pv1InpuPower => _Pv1InpuPower;
public DcPower Pv1InpuPower => _pv1InpuPower;
public DcPower TotalPvPower => (Pv1Voltage * Pv1Current) + (Pv2Voltage * Pv2Current) +
public DcPower PvPower => (Pv1Voltage * Pv1Current) + (Pv2Voltage * Pv2Current) +
(Pv3Voltage * Pv3Current) + (Pv4Voltage * Pv4Current) +
(Pv5Voltage * Pv5Current) + (Pv6Voltage * Pv6Current);
// ********************************** Holding Registers (Control) *************************************************************
@ -173,16 +172,16 @@ public partial class WITGrowatRecord
set => _BatteryMaxDischargePower = value;
}
public Percent ChargeCutoffSoc
public Percent ChargeCutoffSocVoltage
{
get => _ChargeCutoffSoc;
set => _ChargeCutoffSoc = (UInt16)value;
get => _BatteryChargeCutoffVoltage;
set => _BatteryChargeCutoffVoltage = (UInt16)value;
}
public Percent DischargeCutoffSoc
public Percent DischargeCutoffVoltage
{
get => _DischargeCutoffSoc;
set => _DischargeCutoffSoc = (UInt16)value;
get => _BatteryDischargeCutoffVoltage;
set => _BatteryDischargeCutoffVoltage = (UInt16)value;
}
public Percent LoadPriorityDischargeCutoffSoc
@ -226,98 +225,61 @@ public partial class WITGrowatRecord
set => _OffGridDischargeCutoffSoc = (UInt16)(value);
}
public UInt16 BatteryChargeCutoffVoltage
public UInt16 MaxSoc
{
get => _BatteryChargeCutoffVoltage;
set => _BatteryChargeCutoffVoltage = value;
get => _maxSoc;
set => _maxSoc = value;
}
public UInt16 BatteryDischargeCutoffVoltage
public UInt16 MinSoc
{
get => _BatteryDischargeCutoffVoltage;
set => _BatteryDischargeCutoffVoltage = value;
get => _minSoc;
set => _minSoc = value;
}
public Double BatteryMaxChargeCurrent
public Double BatteryMaxChargingCurrent
{
get => _BatteryMaxChargeCurrent;
set => _BatteryMaxChargeCurrent = (UInt16)value;
get => _batteryMaxChargingCurrent;
set => _batteryMaxChargingCurrent = (UInt16)value;
}
public Double BatteryMaxdischargeCurrent
public Double BatteryMaxDischargingCurrent
{
get => _BatteryMaxdischargeCurrent;
set => _BatteryMaxdischargeCurrent = (UInt16) value;
get => _batteryMaxDischargingCurrent;
set => _batteryMaxDischargingCurrent = (UInt16) value;
}
public Double Battery1MaxDischargingCurrent => _batteryMaxDischargingCurrent;
public Double Battery1MaxChargingCurrent => _batteryMaxChargingCurrent;
public Percent Battery1Soc => _BatterySoc1;
public Percent Battery1Soh => _BatterySoh1;
public Current Battery1Current => _BatteryCurrent1;
public Voltage Battery1Voltage => _BatteryVoltage1;
public ActivePower Battery1Power => _BatteryPower1;
public ActivePower Battery1MaxAllowableChargePower => _BatteryMaxAllowableChargePower1;
public ActivePower Battery1MaxAllowableDischargePower => _BatteryMaxAllowableDischargePower1;
public Energy Battery1DailyChargeEnergy => _DailyChargeEnergy1;
public Energy Battery1DailyDischargeEnergy => _DailyDischargeEnergy1;
public Energy Battery1AccumulatedChargeEnergy => _AccumulatedChargeEnergy1;
public Energy Battery1AccumulatedDischargeEnergy => _AccumulatedDishargeEnergy1;
public Temperature Battery1AmbientTemperature => _BatteryAmbientTemperature1;
public IReadOnlyList<BatteryRecord> Batteries => new List<BatteryRecord>
{
new BatteryRecord
{
Soc = _BatterySoc1,
Soh = _BatterySoh1,
//ClusterTotalNumber = _ClusterTotalNumber1,
Current = _BatteryCurrent1,
Voltage = _BatteryVoltage1,
Power = _BatteryPower1,
MaxAllowableChargePower = _BatteryMaxAllowableChargePower1,
MaxAllowableDischargePower = _BatteryMaxAllowableDischargePower1,
DailyChargeEnergy = _DailyChargeEnergy1,
DailyDischargeEnergy = _DailyDischargeEnergy1,
AccumulatedChargeEnergy = _AccumulatedChargeEnergy1,
AccumulatedDischargeEnergy = _AccumulatedDishargeEnergy1,
BatteryAmbientTemperature = _BatteryAmbientTemperature1
public Percent Battery2Soc => _BatterySoc2;
public Percent Battery2Soh => _BatterySoh2;
public Current Battery2Current => _BatteryCurrent2;
public Voltage Battery2Voltage => _BatteryVoltage2;
public ActivePower Battery2Power => _batteryPower2;
public ActivePower Battery2MaxAllowableChargePower => _BatteryMaxAllowableChargePower2;
public ActivePower Battery2MaxAllowableDischargePower => _BatteryMaxAllowableDischargePower2;
public Energy Battery2DailyChargeEnergy => _DailyChargeEnergy2;
public Energy Battery2DailyDischargeEnergy => _DailyDischargeEnergy2;
public Energy Battery2AccumulatedChargeEnergy => _AccumulatedChargeEnergy2;
public Energy Battery2AccumulatedDischargeEnergy => _AccumulatedDischargeEnergy2;
public Temperature Battery2AmbientTemperature => _BatteryAmbientTemperature2;
public Energy BatteryDailyChargeEnergy => _DailyChargeEnergy1 + _DailyChargeEnergy2;
public Energy BatteryDailyDischargeEnergy => _DailyDischargeEnergy1 + _DailyDischargeEnergy2;
}
/*
new BatteryRecord
{
Soc = _BatterySoc2,
Soh = _BatterySoh2,
// ClusterTotalNumber = _ClusterTotalNumber2,
Current = _BatteryCurrent2,
Voltage = _BatteryVoltage2,
Power = _BatteryPower2,
MaxAllowableChargePower = _BatteryMaxAllowableChargePower2,
MaxAllowableDischargePower = _BatteryMaxAllowableDischargePower2,
DailyChargeEnergy = _DailyChargeEnergy2,
DailyDischargeEnergy = _DailyDischargeEnergy2,
AccumulatedChargeEnergy = _AccumulatedChargeEnergy2,
AccumulatedDischargeEnergy = _AccumulatedDischargeEnergy2,
BatteryAmbientTemperature = _BatteryAmbientTemperature2
},*/
/*
new BatteryRecord
{
Soc = _BatterySoc3,
Soh = _BatterySoh3,
ClusterTotalNumber = _ClusterTotalNumber3,
Current = _BatteryCurrent3,
Voltage = _BatteryVoltage3,
Power = _BatteryPower3,
MaxAllowableChargePower = _BatteryMaxAllowableChargePower3,
MaxAllowableDischargePower = _BatteryMaxAllowableDischargePower3,
DailyChargeEnergy = _DailyChargeEnergy3,
DailyDischargeEnergy = _DailyDischargeEnergy3
},
new BatteryRecord
{
Soc = _BatterySoc4,
Soh = _BatterySoh4,
ClusterTotalNumber = _ClusterTotalNumber4,
Current = _BatteryCurrent4,
Voltage = _BatteryVoltage4,
Power = _BatteryPower4,
MaxAllowableChargePower = _BatteryMaxAllowableChargePower4,
MaxAllowableDischargePower = _BatteryMaxAllowableDischargePower4,
DailyChargeEnergy = _DailyChargeEnergy4,
DailyDischargeEnergy = _DailyDischargeEnergy4
}*/
};
public BatteriesRecord? BatteriesRecords => BatteriesRecord.FromBatteries(Batteries);
}

View File

@ -14,36 +14,36 @@ public partial class WITGrowatRecord
[InputRegister<Int32>(8083, Scale = 0.1)] private Int32 _exportedPowerToGrid;
// 3100031009 — Operating Status Info
[InputRegister(31000)] private UInt16 _SystemOperatingMode;
[InputRegister(31001)] private UInt16 _BatteryOperatingMode;
[InputRegister(31002)] private UInt16 _OperatingPriority;
[InputRegister(31003)] private UInt16 _Reserved1;
[InputRegister(31004)] private UInt16 _Reserved2;
[InputRegister(31005)] private UInt16 _FaultMainCode;// Can we change this to warning?
[InputRegister(31006)] private UInt16 _FaultSubCode; // Can we change this to warning?
[InputRegister(31007)] private UInt16 _WarningMainCode;
[InputRegister(31008)] private UInt16 _WarningSubCode;
[InputRegister(31009)] private UInt16 _Reserved3;
[InputRegister(31000)] private UInt16 _systemOperatingMode;
[InputRegister(31001)] private UInt16 _batteryOperatingMode;
[InputRegister(31002)] private UInt16 _operatingPriority;
[InputRegister(31003)] private UInt16 _reserved1;
[InputRegister(31004)] private UInt16 _reserved2;
[InputRegister(31005)] private UInt16 _faultMainCode;// Can we change this to warning?
[InputRegister(31006)] private UInt16 _faultSubCode; // Can we change this to warning?
[InputRegister(31007)] private UInt16 _warningMainCode;
[InputRegister(31008)] private UInt16 _warningSubCode;
[InputRegister(31009)] private UInt16 _reserved3;
// 3101031099 — PV Parameters
[InputRegister(31010,Scale = 0.1)] private Int16 _Pv1Voltage;
[InputRegister(31011,Scale = 0.1)] private Int16 _Pv1Current;
[InputRegister(31012,Scale = 0.1)] private Int16 _Pv2Voltage;
[InputRegister(31013,Scale = 0.1)] private Int16 _Pv2Current;
[InputRegister(31014,Scale = 0.1)] private Int16 _Pv3Voltage;
[InputRegister(31015,Scale = 0.1)] private Int16 _Pv3Current;
[InputRegister(31016,Scale = 0.1)] private Int16 _Pv4Voltage;
[InputRegister(31017,Scale = 0.1)] private Int16 _Pv4Current;
[InputRegister(31018,Scale = 0.1)] private Int16 _Pv5Voltage;
[InputRegister(31019,Scale = 0.1)] private Int16 _Pv5Current;
[InputRegister(31020,Scale = 0.1)] private Int16 _Pv6Voltage;
[InputRegister(31021,Scale = 0.1)] private Int16 _Pv6Current;
[InputRegister(31058)] private Int16 _Pv1InpuPower;
[InputRegister(31010,Scale = 0.1)] private Int16 _pv1Voltage;
[InputRegister(31011,Scale = 0.1)] private Int16 _pv1Current;
[InputRegister(31012,Scale = 0.1)] private Int16 _pv2Voltage;
[InputRegister(31013,Scale = 0.1)] private Int16 _pv2Current;
[InputRegister(31014,Scale = 0.1)] private Int16 _pv3Voltage;
[InputRegister(31015,Scale = 0.1)] private Int16 _pv3Current;
[InputRegister(31016,Scale = 0.1)] private Int16 _pv4Voltage;
[InputRegister(31017,Scale = 0.1)] private Int16 _pv4Current;
[InputRegister(31018,Scale = 0.1)] private Int16 _pv5Voltage;
[InputRegister(31019,Scale = 0.1)] private Int16 _pv5Current;
[InputRegister(31020,Scale = 0.1)] private Int16 _pv6Voltage;
[InputRegister(31021,Scale = 0.1)] private Int16 _pv6Current;
[InputRegister(31058)] private Int16 _pv1InpuPower;
//— AC Side 31100 - 31199
[InputRegister<Int32>(31100, Scale = 0.1)] private Int32 _ActivePower; // Positive: feed to grid, Negative: draw from the grid
[InputRegister<Int32>(31102, Scale = 0.1)] private Int32 _ReactivePower; // Positive: capacitive, Negative: Inductive
[InputRegister(31104, Scale = 0.1)] private Int16 _Reserved4;
[InputRegister(31105, Scale = 0.01)] private UInt16 _Frequency;
[InputRegister<Int32>(31100, Scale = 0.1)] private Int32 _activePower; // Positive: feed to grid, Negative: draw from the grid
[InputRegister<Int32>(31102, Scale = 0.1)] private Int32 _reactivePower; // Positive: capacitive, Negative: Inductive
[InputRegister(31104, Scale = 0.1)] private Int16 _reserved4;
[InputRegister(31105, Scale = 0.01)] private UInt16 _frequency;
[InputRegister(31106, Scale = 0.1)] private UInt16 _GridAbLineVoltage;
[InputRegister(31107, Scale = 0.1)] private UInt16 _GridBcLineVoltage;
@ -88,7 +88,7 @@ public partial class WITGrowatRecord
// 3130031399 — Second Battery Cluster Info (incl. BDC and BMS)
/* [InputRegister<Int32>(31300)] private Int32 _BatteryPower2; // positive Charge, Negative Discharge
[InputRegister<Int32>(31300)] private Int32 _batteryPower2; // positive Charge, Negative Discharge
[InputRegister<UInt32>(31302)] private UInt32 _DailyChargeEnergy2;
[InputRegister<UInt32>(31304)] private UInt32 _AccumulatedChargeEnergy2;
[InputRegister<UInt32>(31206)] private UInt32 _DailyDischargeEnergy2; //0.1kw
@ -171,8 +171,8 @@ public partial class WITGrowatRecord
[HoldingRegister<UInt32>(30400 , writable: true)] private UInt32 _BatteryMaxChargePower; //
[HoldingRegister<UInt32>(30402 , writable: true)] private UInt32 _BatteryMaxDischargePower; //
[HoldingRegister(30404, writable: true)] private UInt16 _ChargeCutoffSoc; //
[HoldingRegister(30405, writable: true)] private UInt16 _DischargeCutoffSoc; //
[HoldingRegister(30404, writable: true)] private UInt16 _maxSoc; //
[HoldingRegister(30405, writable: true)] private UInt16 _minSoc; //
[HoldingRegister(30406, writable: true)] private UInt16 _LoadPriorityDischargeCutoffSoc; //
[HoldingRegister(30407, writable: true)] private Boolean _RemotePowerControl; //
[HoldingRegister(30408, writable: true)] private UInt16 _RemotePowerControlChargeDuration; //
@ -184,6 +184,6 @@ public partial class WITGrowatRecord
[HoldingRegister(30496, writable: true, Scale = 0.1)] private UInt16 _BatteryChargeCutoffVoltage; //
[HoldingRegister(30497, writable: true, Scale = 0.1)] private UInt16 _BatteryDischargeCutoffVoltage; //
[HoldingRegister(30498, writable: true, Scale = 0.1)] private UInt16 _BatteryMaxChargeCurrent; //
[HoldingRegister(30499, writable: true, Scale = 0.1)] private UInt16 _BatteryMaxdischargeCurrent; //*/
[HoldingRegister(30498, writable: true, Scale = 0.1)] private UInt16 _batteryMaxChargingCurrent; //
[HoldingRegister(30499, writable: true, Scale = 0.1)] private UInt16 _batteryMaxDischargingCurrent; //*/
}

View File

@ -41,7 +41,7 @@ public class ModbusDevice<[DynamicallyAccessedMembers(All)] R> where R : notnull
foreach (var batch in _Batches)
{
batch.Read(record);
Thread.Sleep(30); // this added mainly for Growatt reading
//Thread.Sleep(30); // this added mainly for Growatt reading
}
return record;
}
@ -51,7 +51,7 @@ public class ModbusDevice<[DynamicallyAccessedMembers(All)] R> where R : notnull
foreach (var batch in _Batches)
{
batch.Write(record);
Thread.Sleep(50); // this added mainly for Growatt reading
//Thread.Sleep(50); // this added mainly for Growatt reading
}
}
}

View File

@ -0,0 +1,14 @@
namespace InnovEnergy.Lib.Devices.Sinexcel_12K_TL.DataType;
public enum SinexcelWeekDays : byte
{
None = 0b00000000,
Sunday = 0b00000001,
Monday = 0b00000010,
Tuesday = 0b00000100,
Wednesday= 0b00001000,
Thursday = 0b00010000,
Friday = 0b00100000,
Saturday = 0b01000000,
All = 0b01111111
}

View File

@ -1,5 +1,3 @@
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using InnovEnergy.Lib.Devices.Sinexcel_12K_TL.DataType;
using InnovEnergy.Lib.Units;
using InnovEnergy.Lib.Units.Power;
@ -9,6 +7,7 @@ namespace InnovEnergy.Lib.Devices.Sinexcel_12K_TL;
public partial class SinexcelRecord
{
private Int16 _factorFromKwtoW = 1000;
// ───────────────────────────────────────────────
// Public API — Decoded Float Values
// ───────────────────────────────────────────────
@ -30,17 +29,17 @@ public partial class SinexcelRecord
public Current GridCPhaseCurrent => UIntToFloat(_grid_C_Phase_Current);
public Current GridNWireCurrent => UIntToFloat(_grid_N_Wire_Current);
public ApparentPower GridAPhaseApparentPower => UIntToFloat(_gridAPhaseApparentPower);
public ApparentPower GridBPhaseApparentPower => UIntToFloat(_gridBPhaseApparentPower);
public ApparentPower GridCPhaseApparentPower => UIntToFloat(_gridCPhaseApparentPower);
public ApparentPower GridAPhaseApparentPower => UIntToFloat(_gridAPhaseApparentPower) * _factorFromKwtoW;
public ApparentPower GridBPhaseApparentPower => UIntToFloat(_gridBPhaseApparentPower) * _factorFromKwtoW;
public ApparentPower GridCPhaseApparentPower => UIntToFloat(_gridCPhaseApparentPower) * _factorFromKwtoW;
public ActivePower GridAPhaseActivePower => UIntToFloat(_gridAPhaseActivePower);
public ActivePower GridBPhaseActivePower => UIntToFloat(_gridBPhaseActivePower);
public ActivePower GridCPhaseActivePower => UIntToFloat(_gridCPhaseActivePower);
public ActivePower GridAPhaseActivePower => UIntToFloat(_gridAPhaseActivePower) * _factorFromKwtoW;
public ActivePower GridBPhaseActivePower => UIntToFloat(_gridBPhaseActivePower) * _factorFromKwtoW;
public ActivePower GridCPhaseActivePower => UIntToFloat(_gridCPhaseActivePower) * _factorFromKwtoW;
public ReactivePower GridAPhaseReactivePower => UIntToFloat(_gridAPhaseReactivePower);
public ReactivePower GridBPhaseReactivePower => UIntToFloat(_gridBPhaseReactivePower);
public ReactivePower GridCPhaseReactivePower => UIntToFloat(_gridCPhaseReactivePower);
public ReactivePower GridAPhaseReactivePower => UIntToFloat(_gridAPhaseReactivePower) * _factorFromKwtoW;
public ReactivePower GridBPhaseReactivePower => UIntToFloat(_gridBPhaseReactivePower) * _factorFromKwtoW;
public ReactivePower GridCPhaseReactivePower => UIntToFloat(_gridCPhaseReactivePower) * _factorFromKwtoW;
// ───────────────────────────────────────────────
// Load Measurements
@ -60,17 +59,19 @@ public partial class SinexcelRecord
public Current LoadCPhaseCurrent => UIntToFloat(_loadCPhaseCurrent);
public Current LoadNWireCurrent => UIntToFloat(_loadNWireCurrent);
public ApparentPower LoadAPhaseApparentPower => UIntToFloat(_loadAPhaseApparentPower);
public ApparentPower LoadBPhaseApparentPower => UIntToFloat(_loadBPhaseApparentPower);
public ApparentPower LoadCPhaseApparentPower => UIntToFloat(_loadCPhaseApparentPower);
public ApparentPower LoadAPhaseApparentPower => UIntToFloat(_loadAPhaseApparentPower) * _factorFromKwtoW;
public ApparentPower LoadBPhaseApparentPower => UIntToFloat(_loadBPhaseApparentPower) * _factorFromKwtoW;
public ApparentPower LoadCPhaseApparentPower => UIntToFloat(_loadCPhaseApparentPower) * _factorFromKwtoW;
public ActivePower LoadAPhaseActivePower => UIntToFloat(_loadAPhaseActivePower);
public ActivePower LoadBPhaseActivePower => UIntToFloat(_loadBPhaseActivePower);
public ActivePower LoadCPhaseActivePower => UIntToFloat(_loadCPhaseActivePower);
public ActivePower LoadAPhaseActivePower => UIntToFloat(_loadAPhaseActivePower) * _factorFromKwtoW;
public ActivePower LoadBPhaseActivePower => UIntToFloat(_loadBPhaseActivePower) * _factorFromKwtoW;
public ActivePower LoadCPhaseActivePower => UIntToFloat(_loadCPhaseActivePower) * _factorFromKwtoW;
public ReactivePower LoadAPhaseReactivePower => UIntToFloat(_loadAPhaseReactivePower);
public ReactivePower LoadBPhaseReactivePower => UIntToFloat(_loadBPhaseReactivePower);
public ReactivePower LoadCPhaseReactivePower => UIntToFloat(_loadCPhaseReactivePower);
public ActivePower ConsumptionPower => TotalLoadPower;
public ReactivePower LoadAPhaseReactivePower => UIntToFloat(_loadAPhaseReactivePower) * _factorFromKwtoW;
public ReactivePower LoadBPhaseReactivePower => UIntToFloat(_loadBPhaseReactivePower) * _factorFromKwtoW;
public ReactivePower LoadCPhaseReactivePower => UIntToFloat(_loadCPhaseReactivePower) * _factorFromKwtoW;
// ───────────────────────────────────────────────
// Inverter Measurements
@ -83,9 +84,11 @@ public partial class SinexcelRecord
public Voltage InverterBcWireVoltage => UIntToFloat(_inverterBCWireVoltage);
public Voltage InverterCaWireVoltage => UIntToFloat(_inverterCAWireVoltage);
public ActivePower InverterAPhaseActivePower => UIntToFloat(_inverterAPhaseActivePower);
public ActivePower InverterBPhaseActivePower => UIntToFloat(_inverterBPhaseActivePower);
public ActivePower InverterCPhaseActivePower => UIntToFloat(_inverterCPhaseActivePower);
public ActivePower InverterAPhaseActivePower => UIntToFloat(_inverterAPhaseActivePower) * _factorFromKwtoW;
public ActivePower InverterBPhaseActivePower => UIntToFloat(_inverterBPhaseActivePower) * _factorFromKwtoW;
public ActivePower InverterCPhaseActivePower => UIntToFloat(_inverterCPhaseActivePower) * _factorFromKwtoW;
public ActivePower InverterActivePower => InverterAPhaseActivePower + InverterBPhaseActivePower + InverterCPhaseActivePower;
// ───────────────────────────────────────────────
// DC/AC Temperature Sensors (°C)
@ -99,12 +102,14 @@ public partial class SinexcelRecord
// ───────────────────────────────────────────────
// Date / Time Information
// ───────────────────────────────────────────────
public Single Year => UIntToFloat(_year);
public Single Month => UIntToFloat(_month);
public Single Day => UIntToFloat(_day);
public Single Hour => UIntToFloat(_hour);
public Single Minute => UIntToFloat(_minute);
public Single Second => UIntToFloat(_second);
public UInt16 Year => (UInt16) ConvertBitPatternToFloat(_year);
public UInt16 Month => (UInt16) ConvertBitPatternToFloat(_month);
public UInt16 Day => (UInt16) ConvertBitPatternToFloat(_day);
public UInt16 Hour => (UInt16) ConvertBitPatternToFloat(_hour);
public UInt16 Minute => (UInt16) ConvertBitPatternToFloat(_minute);
public UInt16 Second => (UInt16) ConvertBitPatternToFloat(_second);
public DateTime SystemDateTime => new(Year, Month, Day, Hour, Minute, Second);
// ───────────────────────────────────────────────
// Diesel Generator Measurements
@ -112,9 +117,9 @@ public partial class SinexcelRecord
public Voltage DieselGenAPhaseVoltage => ConvertBitPatternToFloat(_dieselGenAPhaseVoltage);
public Voltage DieselGenBPhaseVoltage => ConvertBitPatternToFloat(_dieselGenBPhaseVoltage);
public Voltage DieselGenCPhaseVoltage => ConvertBitPatternToFloat(_dieselGenCPhaseVoltage);
public Voltage DieselGenABWireVoltage => ConvertBitPatternToFloat(_dieselGenABWireVoltage);
public Voltage DieselGenBCWireVoltage => ConvertBitPatternToFloat(_dieselGenBCWireVoltage);
public Voltage DieselGenCAWireVoltage => ConvertBitPatternToFloat(_dieselGenCAWireVoltage);
public Voltage DieselGenAbWireVoltage => ConvertBitPatternToFloat(_dieselGenABWireVoltage);
public Voltage DieselGenBcWireVoltage => ConvertBitPatternToFloat(_dieselGenBCWireVoltage);
public Voltage DieselGenCaWireVoltage => ConvertBitPatternToFloat(_dieselGenCAWireVoltage);
public Frequency DieselGenVoltageFrequency => ConvertBitPatternToFloat(_dieselGenVoltageFrequency);
@ -123,38 +128,39 @@ public partial class SinexcelRecord
public Current DieselGenCPhaseCurrent => ConvertBitPatternToFloat(_dieselGenCPhaseCurrent);
public Current DieselGenNWireCurrent => ConvertBitPatternToFloat(_dieselGenNWireCurrent);
public ApparentPower DieselGenAPhaseApparentPower => ConvertBitPatternToFloat(_dieselGenAPhaseApparentPower);
public ApparentPower DieselGenBPhaseApparentPower => ConvertBitPatternToFloat(_dieselGenBPhaseApparentPower);
public ApparentPower DieselGenCPhaseApparentPower => ConvertBitPatternToFloat(_dieselGenCPhaseApparentPower);
public ApparentPower DieselGenAPhaseApparentPower => ConvertBitPatternToFloat(_dieselGenAPhaseApparentPower) * _factorFromKwtoW;
public ApparentPower DieselGenBPhaseApparentPower => ConvertBitPatternToFloat(_dieselGenBPhaseApparentPower) * _factorFromKwtoW;
public ApparentPower DieselGenCPhaseApparentPower => ConvertBitPatternToFloat(_dieselGenCPhaseApparentPower) * _factorFromKwtoW;
public ActivePower DieselGenAPhaseActivePower => ConvertBitPatternToFloat(_dieselGenAPhaseActivePower);
public ActivePower DieselGenBPhaseActivePower => ConvertBitPatternToFloat(_dieselGenBPhaseActivePower);
public ActivePower DieselGenCPhaseActivePower => ConvertBitPatternToFloat(_dieselGenCPhaseActivePower);
public ActivePower DieselGenAPhaseActivePower => ConvertBitPatternToFloat(_dieselGenAPhaseActivePower) * _factorFromKwtoW;
public ActivePower DieselGenBPhaseActivePower => ConvertBitPatternToFloat(_dieselGenBPhaseActivePower) * _factorFromKwtoW;
public ActivePower DieselGenCPhaseActivePower => ConvertBitPatternToFloat(_dieselGenCPhaseActivePower) * _factorFromKwtoW;
public ReactivePower DieselGenAPhaseReactivePower => ConvertBitPatternToFloat(_dieselGenAPhaseReactivePower);
public ReactivePower DieselGenBPhaseReactivePower => ConvertBitPatternToFloat(_dieselGenBPhaseReactivePower);
public ReactivePower DieselGenCPhaseReactivePower => ConvertBitPatternToFloat(_dieselGenCPhaseReactivePower);
public ReactivePower DieselGenAPhaseReactivePower => ConvertBitPatternToFloat(_dieselGenAPhaseReactivePower) * _factorFromKwtoW;
public ReactivePower DieselGenBPhaseReactivePower => ConvertBitPatternToFloat(_dieselGenBPhaseReactivePower) * _factorFromKwtoW;
public ReactivePower DieselGenCPhaseReactivePower => ConvertBitPatternToFloat(_dieselGenCPhaseReactivePower) * _factorFromKwtoW;
// ───────────────────────────────────────────────
// Photovoltaic and Battery Measurements
// ───────────────────────────────────────────────
public Voltage PvVoltage1 => ConvertBitPatternToFloat(_pvVoltage1);
public Current PvCurrent1 => ConvertBitPatternToFloat(_pvCurrent1);
public ActivePower PvPower1 => ConvertBitPatternToFloat(_pvPower1);
public ActivePower PvPower1 => ConvertBitPatternToFloat(_pvPower1) *_factorFromKwtoW;
public Voltage PvVoltage2 => ConvertBitPatternToFloat(_pvVoltage2);
public Current PvCurrent2 => ConvertBitPatternToFloat(_pvCurrent2);
public ActivePower PvPower2 => ConvertBitPatternToFloat(_pvPower2);
public ActivePower PvPower2 => ConvertBitPatternToFloat(_pvPower2) * _factorFromKwtoW;
public Voltage BatteryVoltage1 => ConvertBitPatternToFloat(_batteryVoltage1);
public Current BatteryCurrent1 => ConvertBitPatternToFloat(_batteryCurrent1);
public ActivePower BatteryPower1 => ConvertBitPatternToFloat(_batteryPower1);
public Percent BatterySoc1 => ConvertBitPatternToFloat(_batterySoc1);
public float BatteryFullLoadDuration1 => ConvertBitPatternToFloat(_batteryFullLoadDuration1);
public Voltage BatteryVoltage2 => ConvertBitPatternToFloat(_batteryVoltage2);
public Current BatteryCurrent2 => ConvertBitPatternToFloat(_batteryCurrent2);
public ActivePower BatteryPower2 => ConvertBitPatternToFloat(_batteryPower2);
public Percent BatterySoc2 => ConvertBitPatternToFloat(_batterySoc2);
public Voltage Battery1Voltage => ConvertBitPatternToFloat(_batteryVoltage1);
public Current Battery1Current => ConvertBitPatternToFloat(_batteryCurrent1);
public ActivePower Battery1Power => ConvertBitPatternToFloat(_batteryPower1) * _factorFromKwtoW;
public Percent Battery1Soc => ConvertBitPatternToFloat(_batterySoc1);
public float BatteryFullLoadDuration1 => ConvertBitPatternToFloat(_batteryFullLoadDuration1); // this is in hour
public Voltage Battery2Voltage => ConvertBitPatternToFloat(_batteryVoltage2);
public Current Battery2Current => ConvertBitPatternToFloat(_batteryCurrent2);
public ActivePower Battery2Power => ConvertBitPatternToFloat(_batteryPower2) * _factorFromKwtoW;
public Percent Battery2Soc => ConvertBitPatternToFloat(_batterySoc2);
public float BatteryFullLoadDuration2 => ConvertBitPatternToFloat(_batteryFullLoadDuration2);
public Temperature DcdcTemperature1 => ConvertBitPatternToFloat(_dcdcTemperature1);
@ -166,8 +172,8 @@ public partial class SinexcelRecord
// ───────────────────────────────────────────────
// Energy and Power Summary
// ───────────────────────────────────────────────
public Energy ElectricityPurchased => ConvertBitPatternToFloat(_electricityPurchased);
public Energy ElectricityFed => ConvertBitPatternToFloat(_electricityFed);
public Energy TotalEnergyToUser => ConvertBitPatternToFloat(_electricityPurchased);
public Energy TotalEnergyToGrid => ConvertBitPatternToFloat(_electricityFed);
public Energy SelfGeneratedElectricity => ConvertBitPatternToFloat(_selfGeneratedElectricity);
public Energy BatteryCharge => ConvertBitPatternToFloat(_batteryCharge);
public Energy BatteryDischarge => ConvertBitPatternToFloat(_batteryDischarge);
@ -175,21 +181,21 @@ public partial class SinexcelRecord
public Energy DailySelfGeneratedElectricity => ConvertBitPatternToFloat(_dailySelfGeneratedElectricity);
public Energy DailyElectricityPurchased => ConvertBitPatternToFloat(_dailyElectricityPurchased);
public Energy DailyElectricityFed => ConvertBitPatternToFloat(_dailyElectricityFed);
public Energy DailyBatteryCharge => ConvertBitPatternToFloat(_dailyBatteryCharge);
public Energy DailyBatteryDischarge => ConvertBitPatternToFloat(_dailyBatteryDischarge);
public Energy BatteryDailyChargeEnergy => ConvertBitPatternToFloat(_dailyBatteryCharge);
public Energy BatteryDailyDischargeEnergy => ConvertBitPatternToFloat(_dailyBatteryDischarge);
public Energy DailyLoadPowerConsumption => ConvertBitPatternToFloat(_dailyLoadPowerConsumption);
public ActivePower TotalPhotovoltaicPower => ConvertBitPatternToFloat(_totalPhotovoltaicPower);
public ActivePower TotalBatteryPower => ConvertBitPatternToFloat(_totalBatteryPower);
public ActivePower TotalLoadPower => ConvertBitPatternToFloat(_totalLoadPower);
public ActivePower TotalGridPower => ConvertBitPatternToFloat(_totalGridPower);
public ActivePower ImportantLoadTotalPower => ConvertBitPatternToFloat(_importantLoadTotalPower);
public ActivePower GeneralLoadTotalPower => ConvertBitPatternToFloat(_generalLoadTotalPower);
public ActivePower TotalPhotovoltaicPower => ConvertBitPatternToFloat(_totalPhotovoltaicPower) * _factorFromKwtoW;
public ActivePower TotalBatteryPower => ConvertBitPatternToFloat(_totalBatteryPower) * _factorFromKwtoW;
public ActivePower TotalLoadPower => ConvertBitPatternToFloat(_totalLoadPower) * _factorFromKwtoW ;
public ActivePower TotalGridPower => ConvertBitPatternToFloat(_totalGridPower) * _factorFromKwtoW ;
public ActivePower ImportantLoadTotalPower => ConvertBitPatternToFloat(_importantLoadTotalPower)* _factorFromKwtoW;
public ActivePower GeneralLoadTotalPower => ConvertBitPatternToFloat(_generalLoadTotalPower)* _factorFromKwtoW;
public Voltage Pv3Voltage => ConvertBitPatternToFloat(_pv3Voltage);
public Current Pv3Current => ConvertBitPatternToFloat(_pv3Current);
public ActivePower Pv3Power => ConvertBitPatternToFloat(_pv3Power);
public ActivePower Pv3Power => ConvertBitPatternToFloat(_pv3Power) * _factorFromKwtoW;
public Voltage Pv4Voltage => ConvertBitPatternToFloat(_pv4Voltage);
public Current Pv4Current => ConvertBitPatternToFloat(_pv4Current);
public ActivePower Pv4Power => ConvertBitPatternToFloat(_pv4Power);
public ActivePower Pv4Power => ConvertBitPatternToFloat(_pv4Power) * _factorFromKwtoW;
public ActivePower GeneratorTotalPower => ConvertBitPatternToFloat(_generatorTotalPower);
// ───────────────────────────────────────────────
@ -209,268 +215,269 @@ public partial class SinexcelRecord
public ApparentPower RatedPowerKva => _ratedPower / 100f; // 0x2008 (value / 100)
public SinexcelModel Model => (SinexcelModel)_model; // 0x200D
public ThreePhaseWireSystem ThreePhaseWireSystem
{
get => (ThreePhaseWireSystem)_threePhaseWireSystem;
set => _threePhaseWireSystem = (UInt32)value;
}
public InputFrequency InputFrequencyClass
{
get => (InputFrequency)_inputFrequencyClass;
set => _inputFrequencyClass = (UInt32)value;
}
//public ThreePhaseWireSystem ThreePhaseWireSystem
//{
// get => (ThreePhaseWireSystem)_threePhaseWireSystem;
// //set => _threePhaseWireSystem = (UInt32)value;
//}
//
//public InputFrequency InputFrequencyClass
//{
// get => (InputFrequency)_inputFrequencyClass;
// //set => _inputFrequencyClass = (UInt32)value;
//}
//
public WorkingMode WorkingMode
{
get => (WorkingMode)ConvertBitPatternToFloat(_workingMode);
set => _workingMode = (UInt32)value;
get => (WorkingMode)(int)BitConverter.Int32BitsToSingle(unchecked((int)_workingMode));
set => _workingMode = BitConverter.ToUInt32(BitConverter.GetBytes((float)value), 0);
}
public GridSwitchMethod GridSwitchMethod
{
get => (GridSwitchMethod)_methodSwitchMode;
set => _methodSwitchMode = (UInt32)value;
}
// ───────────────────────────────────────────────
// Inverter Control Configuration
// ───────────────────────────────────────────────
public SinexcelUnbalanceCompensation EnableOnGridUnbalanceCompensation
{
get => (SinexcelUnbalanceCompensation)_enableOnGridUnbalanceCompensation;
set => _enableOnGridUnbalanceCompensation = (UInt32)value;
}
public SinexcelTemperatureDrop TemperatureDrop
{
get => (SinexcelTemperatureDrop)ConvertBitPatternToFloat(_temperatureDrop);
set => _temperatureDrop = (UInt32)value;
}
public SinexcelHvrt Hvrt
{
get => (SinexcelHvrt)_hvrt;
set => _hvrt = (UInt32)value;
}
public SinexcelLvrt Lvrt
{
get => (SinexcelLvrt)_lvrt;
set => _lvrt = (UInt32)value;
}
// Fan Gear — numeric [0.5 ~ 1.0], default 1.0
public float FanGear
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_fanGear));
set => _fanGear = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
// ───────────────────────────────────────────────
// Battery Configuration
// ───────────────────────────────────────────────
public SinexcelBatteryAccessMethod BatteryAccessMethod
{
get => (SinexcelBatteryAccessMethod)_batteryAccessMethod;
set => _batteryAccessMethod = (UInt32)value;
}
public SinexcelMeterAccessEnable MeterAccessEnable
{
get => (SinexcelMeterAccessEnable)ConvertBitPatternToFloat(_meterAccessEnable);
set => _meterAccessEnable = (UInt32)value;
}
public SinexcelBatteryEnable EnableBattery1
{
get => (SinexcelBatteryEnable)ConvertBitPatternToFloat(_enableBattery1);
set => _enableBattery1 = (UInt32)value;
}
public SinexcelBatteryEnable EnableBattery2
{
get => (SinexcelBatteryEnable)ConvertBitPatternToFloat(_enableBattery2);
set => _enableBattery2 = (UInt32)value;
}
public SinexcelPvEnable EnablePv1
{
get => (SinexcelPvEnable)ConvertBitPatternToFloat(_enablePv1);
set => _enablePv1 = (UInt32)value;
}
public SinexcelPvEnable EnablePv2
{
get => (SinexcelPvEnable)ConvertBitPatternToFloat(_enablePv2);
set => _enablePv2 = (UInt32)value;
}
public SinexcelBatteryType BatteryType
{
get => (SinexcelBatteryType)_batteryType;
set => _batteryType = (UInt32)value;
}
public float BatteryCapacity1
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_batteryCapacity1));
set => _batteryCapacity1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float MaxChargingCurrentBattery1
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_maxChargingCurrentBattery1));
set => _maxChargingCurrentBattery1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float MaxDischargingCurrentBattery1
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_maxDischargingCurrentBattery1));
set => _maxDischargingCurrentBattery1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float RatedBatteryVoltage1
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_ratedBatteryVoltage1));
set => _ratedBatteryVoltage1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float MinSocBattery1
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_minSocBattery1));
set => _minSocBattery1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float SetValueBattery1
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_setValueBattery1));
set => _setValueBattery1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public SinexcelActiveChargeDischarge ActiveChargeDischarge
{
get => (SinexcelActiveChargeDischarge)ConvertBitPatternToFloat(_activeChargeDischarge);
set => _activeChargeDischarge = (UInt32)value;
}
public float ActiveChargeDischargePower
{
get => ConvertBitPatternToFloat(_activeChargeDischargePower);
set => _activeChargeDischargePower = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
// ───────────────────────────────────────────────
// Protection & PV Mode
// ───────────────────────────────────────────────
public SinexcelIslandProtection EnableIslandProtection
{
get => (SinexcelIslandProtection)_enableIslandProtection;
set => _enableIslandProtection = (UInt32)value;
}
public SinexcelPvAccessMode PvAccessMode
{
get => (SinexcelPvAccessMode)_pvAccessMode;
set => _pvAccessMode = (UInt32)value;
}
// ───────────────────────────────────────────────
// System-Level Parameters
// ───────────────────────────────────────────────
public float OutputVoltageAdjustmentFactor
{
get => BitConverter.Int32BitsToSingle(unchecked((int)_outputVoltageAdjustmentFactor));
set => _outputVoltageAdjustmentFactor = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float SetValueBatteryUndervoltage1
{
get => BitConverter.Int32BitsToSingle(unchecked((int)_setValueBatteryUndervoltage1));
set => _setValueBatteryUndervoltage1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float InverterPowerLimit
{
get => BitConverter.Int32BitsToSingle(unchecked((int)_inverterPowerLimit));
set => _inverterPowerLimit = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
// ───────────────────────────────────────────────
// Battery 2 Parameters
// ───────────────────────────────────────────────
public float Battery2Capacity
{
get => BitConverter.Int32BitsToSingle(unchecked((int)_battery2Capacity));
set => _battery2Capacity = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float MaxChargingCurrentBattery2
{
get => BitConverter.Int32BitsToSingle(unchecked((int)_maxChargingCurrentBattery2));
set => _maxChargingCurrentBattery2 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float MaxDischargingCurrentBattery2
{
get => BitConverter.Int32BitsToSingle(unchecked((int)_maxDischargingCurrentBattery2));
set => _maxDischargingCurrentBattery2 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float Battery2RatedVoltage
{
get => BitConverter.Int32BitsToSingle(unchecked((int)_battery2RatedVoltage));
set => _battery2RatedVoltage = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float Battery2MinSoc
{
get => BitConverter.Int32BitsToSingle(unchecked((int)_battery2MinSoc));
set => _battery2MinSoc = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float Battery2OverVoltageSetting
{
get => BitConverter.Int32BitsToSingle(unchecked((int)_battery2OverVoltageSetting));
set => _battery2OverVoltageSetting = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float Battery2UnderVoltageSetpoint
{
get => BitConverter.Int32BitsToSingle(unchecked((int)_battery2UnderVoltageSetpoint));
set => _battery2UnderVoltageSetpoint = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
// ───────────────────────────────────────────────
// Parallel / System Settings
// ───────────────────────────────────────────────
public SinexcelMachineMode MachineMode
{
get => (SinexcelMachineMode)ConvertBitPatternToFloat(_singleOrParallelMachine);
set => _singleOrParallelMachine = (UInt32)value;
}
public UInt32 NumberOfSystemModules
{
get => (UInt32)ConvertBitPatternToFloat(_numberOfSystemModules);
set => _numberOfSystemModules = value;
}
public UInt32 ParallelModuleMachineNumber
{
get => (UInt32)ConvertBitPatternToFloat(_parallelModuleMachineNumber);
set => _parallelModuleMachineNumber = value;
}
public AccreditedCountry AccreditedCountry
{
get => (AccreditedCountry)ConvertBitPatternToFloat(_accreditedCountries);
set => _accreditedCountries = (UInt32)value;
}
// ───────────────────────────────────────────────
// Control Commands
// ───────────────────────────────────────────────
//
//public GridSwitchMethod GridSwitchMethod
//{
// get => (GridSwitchMethod)_methodSwitchMode;
// //set => _methodSwitchMode = (UInt32)value;
//}
//
//// ───────────────────────────────────────────────
//// Inverter Control Configuration
//// ───────────────────────────────────────────────
//public SinexcelUnbalanceCompensation EnableOnGridUnbalanceCompensation
//{
// get => (SinexcelUnbalanceCompensation)_enableOnGridUnbalanceCompensation;
// //set => _enableOnGridUnbalanceCompensation = (UInt32)value;
//}
//
//public SinexcelTemperatureDrop TemperatureDrop
//{
// get => (SinexcelTemperatureDrop)ConvertBitPatternToFloat(_temperatureDrop);
// //set => _temperatureDrop = (UInt32)value;
//}
//
//public SinexcelHvrt Hvrt
//{
// get => (SinexcelHvrt)_hvrt;
// //set => _hvrt = (UInt32)value;
//}
//
//public SinexcelLvrt Lvrt
//{
// get => (SinexcelLvrt)_lvrt;
// //set => _lvrt = (UInt32)value;
//}
//
// F//an Gear — numeric [0.5 ~ 1.0], default 1.0
//public float FanGear
//{
// get => BitConverter.Int32BitsToSingle(unchecked((Int32)_fanGear));
// //set => _fanGear = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//// ───────────────────────────────────────────────
//// Battery Configuration
//// ───────────────────────────────────────────────
//public SinexcelBatteryAccessMethod BatteryAccessMethod
//{
// get => (SinexcelBatteryAccessMethod)_batteryAccessMethod;
// //set => _batteryAccessMethod = (UInt32)value;
//}
//
//public SinexcelMeterAccessEnable MeterAccessEnable
//{
// get => (SinexcelMeterAccessEnable)ConvertBitPatternToFloat(_meterAccessEnable);
// //set => _meterAccessEnable = (UInt32)value;
//}
//
//public SinexcelBatteryEnable EnableBattery1
//{
// get => (SinexcelBatteryEnable)ConvertBitPatternToFloat(_enableBattery1);
// //set => _enableBattery1 = (UInt32)value;
//}
//
//public SinexcelBatteryEnable EnableBattery2
//{
// get => (SinexcelBatteryEnable)ConvertBitPatternToFloat(_enableBattery2);
// //set => _enableBattery2 = (UInt32)value;
//}
//
//public SinexcelPvEnable EnablePv1
//{
// get => (SinexcelPvEnable)ConvertBitPatternToFloat(_enablePv1);
// //set => _enablePv1 = (UInt32)value;
//}
//
//public SinexcelPvEnable EnablePv2
//{
// get => (SinexcelPvEnable)ConvertBitPatternToFloat(_enablePv2);
// //set => _enablePv2 = (UInt32)value;
//}
//
//public SinexcelBatteryType BatteryType
//{
// get => (SinexcelBatteryType)_batteryType;
// //set => _batteryType = (UInt32)value;
//}
//
//public float BatteryCapacity1
//{
// get => BitConverter.Int32BitsToSingle(unchecked((Int32)_batteryCapacity1));
// //set => _batteryCapacity1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public float Battery1MaxChargingCurrent
//{
// get => BitConverter.Int32BitsToSingle(unchecked((Int32)_maxChargingCurrentBattery1));
// //set => _maxChargingCurrentBattery1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public float Battery1MaxDischargingCurrent
//{
// get => BitConverter.Int32BitsToSingle(unchecked((Int32)_maxDischargingCurrentBattery1));
// //set => _maxDischargingCurrentBattery1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public float RatedBatteryVoltage1
//{
// get => BitConverter.Int32BitsToSingle(unchecked((Int32)_ratedBatteryVoltage1));
// //set => _ratedBatteryVoltage1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public float Battery1MinSoc
//{
// get => BitConverter.Int32BitsToSingle(unchecked((Int32)_minSocBattery1));
// //set => _minSocBattery1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public float SetValueBattery1
//{
// get => BitConverter.Int32BitsToSingle(unchecked((Int32)_setValueBattery1));
// //set => _setValueBattery1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public SinexcelActiveChargeDischarge ActiveChargeDischarge
//{
// get => (SinexcelActiveChargeDischarge)ConvertBitPatternToFloat(_activeChargeDischarge);
// //set => _activeChargeDischarge = (UInt32)value;
//}
//
//public float ActiveChargeDischargePower
//{
// get => ConvertBitPatternToFloat(_activeChargeDischargePower) * _factorFromKwtoW;
// //set => _activeChargeDischargePower = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0); // we should check this may need to convert from W to KW
//}
//
//// ───────────────────────────────────────────────
//// Protection & PV Mode
//// ───────────────────────────────────────────────
//public SinexcelIslandProtection EnableIslandProtection
//{
// get => (SinexcelIslandProtection)_enableIslandProtection;
// //set => _enableIslandProtection = (UInt32)value;
//}
//
//public SinexcelPvAccessMode PvAccessMode
//{
// get => (SinexcelPvAccessMode)_pvAccessMode;
// //set => _pvAccessMode = (UInt32)value;
//}
//
//// ───────────────────────────────────────────────
//// System-Level Parameters
//// ───────────────────────────────────────────────
//public float OutputVoltageAdjustmentFactor
//{
// get => BitConverter.Int32BitsToSingle(unchecked((int)_outputVoltageAdjustmentFactor));
// //set => _outputVoltageAdjustmentFactor = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public float SetValueBatteryUndervoltage1
//{
// get => BitConverter.Int32BitsToSingle(unchecked((int)_setValueBatteryUndervoltage1));
// //set => _setValueBatteryUndervoltage1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public float InverterPowerLimit
//{
// get => BitConverter.Int32BitsToSingle(unchecked((int)_inverterPowerLimit));
// //set => _inverterPowerLimit = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//// ───────────────────────────────────────────────
//// Battery 2 Parameters
//// ───────────────────────────────────────────────
//public float Battery2Capacity
//{
// get => BitConverter.Int32BitsToSingle(unchecked((int)_battery2Capacity));
// //set => _battery2Capacity = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public float Battery2MaxChargingCurrent
//{
// get => BitConverter.Int32BitsToSingle(unchecked((int)_maxChargingCurrentBattery2));
// //set => _maxChargingCurrentBattery2 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public float Battery2MaxDischargingCurrent
//{
// get => BitConverter.Int32BitsToSingle(unchecked((int)_maxDischargingCurrentBattery2));
// //set => _maxDischargingCurrentBattery2 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public float Battery2RatedVoltage
//{
// get => BitConverter.Int32BitsToSingle(unchecked((int)_battery2RatedVoltage));
// //set => _battery2RatedVoltage = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public float Battery2MinSoc
//{
// get => BitConverter.Int32BitsToSingle(unchecked((int)_battery2MinSoc));
// //set => _battery2MinSoc = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public float Battery2OverVoltageSetting
//{
// get => BitConverter.Int32BitsToSingle(unchecked((int)_battery2OverVoltageSetting));
// //set => _battery2OverVoltageSetting = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public float Battery2UnderVoltageSetpoint
//{
// get => BitConverter.Int32BitsToSingle(unchecked((int)_battery2UnderVoltageSetpoint));
// //set => _battery2UnderVoltageSetpoint = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//// ───────────────────────────────────────────────
//// Parallel / System Settings
//// ───────────────────────────────────────────────
//public SinexcelMachineMode MachineMode
//{
// get => (SinexcelMachineMode)ConvertBitPatternToFloat(_singleOrParallelMachine);
// //set => _singleOrParallelMachine = (UInt32)value;
//}
//
//public UInt32 NumberOfSystemModules
//{
// get => (UInt32)ConvertBitPatternToFloat(_numberOfSystemModules);
// //set => _numberOfSystemModules = value;
//}
//
//public UInt32 ParallelModuleMachineNumber
//{
// get => (UInt32)ConvertBitPatternToFloat(_parallelModuleMachineNumber);
// //set => _parallelModuleMachineNumber = value;
//}
//
//public AccreditedCountry AccreditedCountry
//{
// get => (AccreditedCountry)ConvertBitPatternToFloat(_accreditedCountries);
// //set => _accreditedCountries = (UInt32)value;
//}
//
//// ───────────────────────────────────────────────
//// Control Commands
//// ───────────────────────────────────────────────
public float PowerOn
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_powerOn));
@ -482,45 +489,39 @@ public partial class SinexcelRecord
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_powerOff));
set => _powerOff = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float FaultClearing
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_faultClearing));
set => _faultClearing = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
// ───────────────────────────────────────────────
// Meter & Battery Control
// ───────────────────────────────────────────────
public float MeterReverseManualDetection
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_meterReverseManualDetection));
set => _meterReverseManualDetection = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public Voltage BatteryVoltage
{
get => (Voltage)ConvertBitPatternToFloat(_batteryVoltage);
set => _batteryVoltage = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public SinexcelBatteryRating BatteryRating
{
get => (SinexcelBatteryRating)ConvertBitPatternToFloat(_batteryRating);
set => _batteryRating = (UInt32)value;
}
public float Battery1Activation
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_battery1Activation));
set => _battery1Activation = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float Battery2Activation
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_battery2Activation));
set => _battery2Activation = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
//
//public float FaultClearingf
//{
// get => BitConverter.Int32BitsToSingle(unchecked((Int32)_faultClearing));
// // //set => _faultClearing = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//// ───────────────────────────────────────────────
//// Meter & Battery Control
//// ───────────────────────────────────────────────
//public float MeterReverseManualDetection
//{
// get => BitConverter.Int32BitsToSingle(unchecked((Int32)_meterReverseManualDetection));
// //set => _meterReverseManualDetection = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public SinexcelBatteryRating BatteryVoltageRating
//{
// get => (SinexcelBatteryRating)ConvertBitPatternToFloat(_batteryVoltageRating);
// //set => _batteryVoltageRating = (UInt32)value;
//}
//
//public float Battery1Activation
//{
// get => BitConverter.Int32BitsToSingle(unchecked((Int32)_battery1Activation));
// //set => _battery1Activation = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
//
//public float Battery2Activation
//{
// get => BitConverter.Int32BitsToSingle(unchecked((Int32)_battery2Activation));
// //set => _battery2Activation = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
// ───────────────────────────────────────────────
// Electric Meter Operating State
@ -571,23 +572,149 @@ public partial class SinexcelRecord
// ───────────────────────────────────────────────
public ActivePower ElectricMeterAPhaseActivePower
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_electricMeterAPhaseActivePower));
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_electricMeterAPhaseActivePower)) * _factorFromKwtoW;
}
public ActivePower ElectricMeterBPhaseActivePower
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_electricMeterBPhaseActivePower));
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_electricMeterBPhaseActivePower)) * _factorFromKwtoW;
}
public ActivePower ElectricMeterCPhaseActivePower
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_electricMeterCPhaseActivePower));
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_electricMeterCPhaseActivePower)) * _factorFromKwtoW;
}
public ActivePower GridPower
{
get => ElectricMeterAPhaseActivePower + ElectricMeterBPhaseActivePower + ElectricMeterCPhaseActivePower;
}
// Energy (kW·h)
public Energy Battery1TotalChargingEnergy => BitConverter.Int32BitsToSingle(unchecked((Int32)_batteryCab1TotalChargingEnergy)); // 0xB0FC
public Energy Battery1TotalDischargedEnergy => BitConverter.Int32BitsToSingle(unchecked((Int32)_batteryCab1TotalDischargedEnergy)); // 0xB0FE
// Pack totals and status
public Voltage Battery1PackTotalVoltage => BitConverter.Int32BitsToSingle(unchecked((Int32)_batteryCab1PackTotalVoltage)); // 0xB100 (0.01 V resolution per spec)
public Current Battery1PackTotalCurrent => BitConverter.Int32BitsToSingle(unchecked((Int32)_batteryCab1PackTotalCurrent)); // 0xB102 (0.01 A resolution per spec)
public Temperature Battery1Temperature => BitConverter.Int32BitsToSingle(unchecked((Int32)_batteryCab1Temperature)); // 0xB104 (0.01 °C resolution per spec)
public Percent Battery1SocSecondvalue => BitConverter.Int32BitsToSingle(unchecked((Int32)_batteryCab1Soc)); // 0xB106 %
public Percent Battery1Soh => BitConverter.Int32BitsToSingle(unchecked((Int32)_batteryCab1Soh)); // 0xB108 %
// Energy (kW·h)
public float Battery2TotalChargingEnergy => BitConverter.Int32BitsToSingle(unchecked((Int32)_batteryCab2TotalChargingEnergy)); // 0xB1FC
public float Battery2TotalDischargedEnergy => BitConverter.Int32BitsToSingle(unchecked((Int32)_batteryCab2TotalDischargedEnergy)); // 0xB1FE
// Pack Voltage / Current / Temperature
public Voltage Battery2PackTotalVoltage => BitConverter.Int32BitsToSingle(unchecked((Int32)_batteryCab2PackTotalVoltage)); // 0xB200 (0.01 V resolution)
public Current Battery2PackTotalCurrent => BitConverter.Int32BitsToSingle(unchecked((Int32)_batteryCab2PackTotalCurrent)); // 0xB202 (0.01 A resolution)
public Temperature Battery2Socsecondvalue => BitConverter.Int32BitsToSingle(unchecked((Int32)_batteryCab2Soc)); // 0xB206 %
public Percent Battery2Soh => BitConverter.Int32BitsToSingle(unchecked((Int32)_batteryCab2Soh)); // 0xB208 %
// Repetitive-week mask (bit-mapped 06 = SunSat)
//public float TimedChargeAndDischargeOff
//{
// get => BitConverter.Int32BitsToSingle(unchecked((Int32)_Timed_Charge_and_Discharge_Off)) ; // only 7 bits used
// //set => _Timed_Charge_and_Discharge_Off = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
//}
// Repetitive-week mask (bit-mapped 06 = SunSat)
/* public float OtherTimePeriodMode
{
get => _Other_time_period_mode ; // only 7 bits used
//set => _Other_time_period_mode = (UInt32)value;
}*/
// Repetitive-week mask (bit-mapped 06 = SunSat)
public SinexcelWeekDays RepetitiveWeeks
{
get => (SinexcelWeekDays)(_repetitiveWeeks & 0x7F); // only 7 bits used
set => _repetitiveWeeks = (UInt32)value;
}
//
// Effective start / end as UNIX timestamps
public DateTime EffectiveStartDate
{
get => DateTimeOffset.FromUnixTimeSeconds(_effectiveStartDate).DateTime;
set => _effectiveStartDate = (UInt32)new DateTimeOffset(value).ToUnixTimeSeconds();
}
//
public DateTime EffectiveEndDate
{
get => DateTimeOffset.FromUnixTimeSeconds(_effectiveEndDate).DateTime;
set => _effectiveEndDate = (UInt32)new DateTimeOffset(value).ToUnixTimeSeconds();
}
// // Charging power during time period 1 (kW)
public float ChargingPowerPeriod1
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_chargingPowerPeriod1));
set => _chargingPowerPeriod1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
public float DishargingPowerPeriod1
{
get => BitConverter.Int32BitsToSingle(unchecked((Int32)_dischargingPowerPeriod1));
set => _dischargingPowerPeriod1 = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
}
// ───────────────────────────────────────────────
// Charging period 1
// ───────────────────────────────────────────────
public TimeSpan ChargeStartTimePeriod1
{
get => ConvertToTimeSpan(_chargeStartTimePeriod1);
set => _chargeStartTimePeriod1 = ConvertFromTimeSpan(value);
}
public TimeSpan ChargeEndTimePeriod1
{
get => ConvertToTimeSpan(_chargeEndTimePeriod1);
set => _chargeEndTimePeriod1 = ConvertFromTimeSpan(value);
}
// ───────────────────────────────────────────────
// Discharging period 1
// ───────────────────────────────────────────────
public TimeSpan DischargeStartTimePeriod1
{
get => ConvertToTimeSpan(_dischargeStartTimePeriod1);
set => _dischargeStartTimePeriod1 = ConvertFromTimeSpan(value);
}
//
public TimeSpan DischargeEndTimePeriod1
{
get => ConvertToTimeSpan(_dischargeEndTimePeriod1);
set => _dischargeEndTimePeriod1 = ConvertFromTimeSpan(value);
}
// ───────────────────────────────────────────────
// Conversion methodes
// ───────────────────────────────────────────────
private static TimeSpan ConvertToTimeSpan(UInt32 raw)
{
// raw is IEEE754 float bits, e.g. 0x44640000 for 912.0
float f = BitConverter.Int32BitsToSingle(unchecked((int)raw));
int hhmm = (int)Math.Round(f);
int hours = hhmm / 100;
int minutes = hhmm % 100;
return new TimeSpan(hours, minutes, 0);
}
private static UInt32 ConvertFromTimeSpan(TimeSpan time)
{
int hhmm = time.Hours * 100 + time.Minutes; // e.g. 9*100+12 = 912
float f = (float)hhmm; // 912.0f
// convert float to raw IEEE754 bits
return BitConverter.ToUInt32(BitConverter.GetBytes(f), 0); // e.g. 0x44640000
}
private static Single IntToFloat(Int32 intValue)
{
byte[] intBytes = BitConverter.GetBytes(intValue);

View File

@ -226,71 +226,70 @@ public partial class SinexcelRecord
// ───────────────────────────────────────────────
// System configuration / operation registers
// ───────────────────────────────────────────────
[HoldingRegister<UInt32>(12294, writable: true)] private UInt32 _threePhaseWireSystem; // 0x3006
[HoldingRegister<UInt32>(12296, writable: true)] private UInt32 _remainnotused; // 0x3008
[HoldingRegister<UInt32>(12298, writable: true)] private UInt32 _inputFrequencyClass; // 0x300A
//[HoldingRegister<UInt32>(12294, writable: true)] private UInt32 _threePhaseWireSystem; // 0x3006
//[HoldingRegister<UInt32>(12296, writable: true)] private UInt32 _remainnotused; // 0x3008
//[HoldingRegister<UInt32>(12298, writable: true)] private UInt32 _inputFrequencyClass; // 0x300A
[HoldingRegister<UInt32>(12300, writable: true)] private UInt32 _workingMode; // 0x300C
[HoldingRegister<UInt32>(12302, writable: true)] private UInt32 _methodSwitchMode; // 0x300E
//[HoldingRegister<UInt32>(12302, writable: true)] private UInt32 _methodSwitchMode; // 0x300E
// ───────────────────────────────────────────────
// Inverter Control and Protection Configuration
// ───────────────────────────────────────────────
[HoldingRegister<UInt32>(12304, writable: true)] private UInt32 _enableOnGridUnbalanceCompensation; // 0x3010
[HoldingRegister<UInt32>(12306, writable: true)] private UInt32 _temperatureDrop; // 0x3012
[HoldingRegister<UInt32>(12308, writable: true)] private UInt32 _hvrt; // 0x3014
[HoldingRegister<UInt32>(12310, writable: true)] private UInt32 _lvrt; // 0x3016
[HoldingRegister<UInt32>(12312, writable: true)] private UInt32 _fanGear; // 0x3018
//[HoldingRegister<UInt32>(12304, writable: true)] private UInt32 _enableOnGridUnbalanceCompensation; // 0x3010
//[HoldingRegister<UInt32>(12306, writable: true)] private UInt32 _temperatureDrop; // 0x3012
//[HoldingRegister<UInt32>(12308, writable: true)] private UInt32 _hvrt; // 0x3014
//[HoldingRegister<UInt32>(12310, writable: true)] private UInt32 _lvrt; // 0x3016
//[HoldingRegister<UInt32>(12312, writable: true)] private UInt32 _fanGear; // 0x3018
// ───────────────────────────────────────────────
// Battery & PV Configuration
// ───────────────────────────────────────────────
[HoldingRegister<UInt32>(12336, writable: true)] private UInt32 _batteryAccessMethod; // 0x3030
[HoldingRegister<UInt32>(12338, writable: true)] private UInt32 _meterAccessEnable; // 0x3032
[HoldingRegister<UInt32>(12340, writable: true)] private UInt32 _enableBattery1; // 0x3034
[HoldingRegister<UInt32>(12342, writable: true)] private UInt32 _enableBattery2; // 0x3036
[HoldingRegister<UInt32>(12344, writable: true)] private UInt32 _enablePv1; // 0x3038
[HoldingRegister<UInt32>(12346, writable: true)] private UInt32 _enablePv2; // 0x303A
[HoldingRegister<UInt32>(12348, writable: true)] private UInt32 _batteryType; // 0x303C
[HoldingRegister<UInt32>(12350, writable: true)] private UInt32 _batteryCapacity1; // 0x303E
[HoldingRegister<UInt32>(12352, writable: true)] private UInt32 _maxChargingCurrentBattery1; // 0x3040
[HoldingRegister<UInt32>(12354, writable: true)] private UInt32 _maxDischargingCurrentBattery1; // 0x3042
[HoldingRegister<UInt32>(12362, writable: true)] private UInt32 _ratedBatteryVoltage1; // 0x304A
[HoldingRegister<UInt32>(12358, writable: true)] private UInt32 _minSocBattery1; // 0x3046
[HoldingRegister<UInt32>(12360, writable: true)] private UInt32 _setValueBattery1; // 0x3048
[HoldingRegister<UInt32>(12364, writable: true)] private UInt32 _activeChargeDischarge; // 0x304A
[HoldingRegister<UInt32>(12366, writable: true)] private UInt32 _activeChargeDischargePower; // 0x304C
[HoldingRegister<UInt32>(12380, writable: true)] private UInt32 _enableIslandProtection; // 0x305C
[HoldingRegister<UInt32>(12382, writable: true)] private UInt32 _pvAccessMode; // 0x305E
//[HoldingRegister<UInt32>(12336, writable: true)] private UInt32 _batteryAccessMethod; // 0x3030
//[HoldingRegister<UInt32>(12338, writable: true)] private UInt32 _meterAccessEnable; // 0x3032
//[HoldingRegister<UInt32>(12340, writable: true)] private UInt32 _enableBattery1; // 0x3034
//[HoldingRegister<UInt32>(12342, writable: true)] private UInt32 _enableBattery2; // 0x3036
//[HoldingRegister<UInt32>(12344, writable: true)] private UInt32 _enablePv1; // 0x3038
//[HoldingRegister<UInt32>(12346, writable: true)] private UInt32 _enablePv2; // 0x303A
//[HoldingRegister<UInt32>(12348, writable: true)] private UInt32 _batteryType; // 0x303C
//[HoldingRegister<UInt32>(12350, writable: true)] private UInt32 _batteryCapacity1; // 0x303E
//[HoldingRegister<UInt32>(12352, writable: true)] private UInt32 _maxChargingCurrentBattery1; // 0x3040
//[HoldingRegister<UInt32>(12354, writable: true)] private UInt32 _maxDischargingCurrentBattery1; // 0x3042
//[HoldingRegister<UInt32>(12362, writable: true)] private UInt32 _ratedBatteryVoltage1; // 0x304A
//[HoldingRegister<UInt32>(12358, writable: true)] private UInt32 _minSocBattery1; // 0x3046
//[HoldingRegister<UInt32>(12360, writable: true)] private UInt32 _setValueBattery1; // 0x3048
//[HoldingRegister<UInt32>(12364, writable: true)] private UInt32 _activeChargeDischarge; // 0x304A
//[HoldingRegister<UInt32>(12366, writable: true)] private UInt32 _activeChargeDischargePower; // 0x304C
//[HoldingRegister<UInt32>(12380, writable: true)] private UInt32 _enableIslandProtection; // 0x305C
//[HoldingRegister<UInt32>(12382, writable: true)] private UInt32 _pvAccessMode; // 0x305E
// ───────────────────────────────────────────────
// System & Battery-2 Configuration
// ───────────────────────────────────────────────
[HoldingRegister<UInt32>(12384, writable: true)] private UInt32 _outputVoltageAdjustmentFactor; // 0x3060
[HoldingRegister<UInt32>(12386, writable: true)] private UInt32 _setValueBatteryUndervoltage1; // 0x3062
[HoldingRegister<UInt32>(12388, writable: true)] private UInt32 _inverterPowerLimit; // 0x3064
[HoldingRegister<UInt32>(12400, writable: true)] private UInt32 _battery2Capacity; // 0x30B0
[HoldingRegister<UInt32>(12402, writable: true)] private UInt32 _maxChargingCurrentBattery2; // 0x30B2
[HoldingRegister<UInt32>(12404, writable: true)] private UInt32 _maxDischargingCurrentBattery2; // 0x30B4
[HoldingRegister<UInt32>(12406, writable: true)] private UInt32 _battery2RatedVoltage; // 0x30B6
[HoldingRegister<UInt32>(12408, writable: true)] private UInt32 _battery2MinSoc; // 0x30B8
[HoldingRegister<UInt32>(12410, writable: true)] private UInt32 _battery2OverVoltageSetting; // 0x30BA
[HoldingRegister<UInt32>(12412, writable: true)] private UInt32 _battery2UnderVoltageSetpoint; // 0x30BC
[HoldingRegister<UInt32>(12414, writable: true)] private UInt32 _singleOrParallelMachine; // 0x30BE
[HoldingRegister<UInt32>(12416, writable: true)] private UInt32 _numberOfSystemModules; // 0x30C0
[HoldingRegister<UInt32>(12418, writable: true)] private UInt32 _parallelModuleMachineNumber; // 0x30C2
[HoldingRegister<UInt32>(12420, writable: true)] private UInt32 _accreditedCountries; // 0x30C4
//[HoldingRegister<UInt32>(12384, writable: true)] private UInt32 _outputVoltageAdjustmentFactor; // 0x3060
//[HoldingRegister<UInt32>(12386, writable: true)] private UInt32 _setValueBatteryUndervoltage1; // 0x3062
//[HoldingRegister<UInt32>(12388, writable: true)] private UInt32 _inverterPowerLimit; // 0x3064
//[HoldingRegister<UInt32>(12400, writable: true)] private UInt32 _battery2Capacity; // 0x30B0
//[HoldingRegister<UInt32>(12402, writable: true)] private UInt32 _maxChargingCurrentBattery2; // 0x30B2
//[HoldingRegister<UInt32>(12404, writable: true)] private UInt32 _maxDischargingCurrentBattery2; // 0x30B4
//[HoldingRegister<UInt32>(12406, writable: true)] private UInt32 _battery2RatedVoltage; // 0x30B6
//[HoldingRegister<UInt32>(12408, writable: true)] private UInt32 _battery2MinSoc; // 0x30B8
//[HoldingRegister<UInt32>(12410, writable: true)] private UInt32 _battery2OverVoltageSetting; // 0x30BA
//[HoldingRegister<UInt32>(12412, writable: true)] private UInt32 _battery2UnderVoltageSetpoint; // 0x30BC
//
//[HoldingRegister<UInt32>(12414, writable: true)] private UInt32 _singleOrParallelMachine; // 0x30BE
//[HoldingRegister<UInt32>(12416, writable: true)] private UInt32 _numberOfSystemModules; // 0x30C0
//[HoldingRegister<UInt32>(12418, writable: true)] private UInt32 _parallelModuleMachineNumber; // 0x30C2
//[HoldingRegister<UInt32>(12420, writable: true)] private UInt32 _accreditedCountries; // 0x30C4
// ───────────────────────────────────────────────
// System Control & Diagnostic Registers
// ───────────────────────────────────────────────
[HoldingRegister<UInt32>(15426, writable: true)] private UInt32 _powerOn; // 0x3C42
[HoldingRegister<UInt32>(15428, writable: true)] private UInt32 _powerOff; // 0x3C44
[HoldingRegister<UInt32>(15430, writable: true)] private UInt32 _faultClearing; // 0x3C46
[HoldingRegister<UInt32>(15518, writable: true)] private UInt32 _meterReverseManualDetection; // 0x3C9E
[HoldingRegister<UInt32>(15520, writable: true)] private UInt32 _batteryVoltage; // 0x3CA0
[HoldingRegister<UInt32>(15522, writable: true)] private UInt32 _batteryRating; // 0x3CA2
[HoldingRegister<UInt32>(15524, writable: true)] private UInt32 _battery1Activation; // 0x3CA4
[HoldingRegister<UInt32>(15526, writable: true)] private UInt32 _battery2Activation; // 0x3CA6
//[HoldingRegister<UInt32>(15430, writable: true)] private UInt32 _faultClearing; // 0x3C46
//[HoldingRegister<UInt32>(15518, writable: true)] private UInt32 _meterReverseManualDetection; // 0x3C9E
//[HoldingRegister<UInt32>(15520, writable: true)] private UInt32 _batteryVoltageRating; // 0x3CA0
//[HoldingRegister<UInt32>(15524, writable: true)] private UInt32 _battery1Activation; // 0x3CA4
//[HoldingRegister<UInt32>(15526, writable: true)] private UInt32 _battery2Activation; // 0x3CA6
// ───────────────────────────────────────────────
@ -310,4 +309,49 @@ public partial class SinexcelRecord
[HoldingRegister<UInt32>(41236)] private UInt32 _electricMeterBPhaseActivePower; // 0xA114
[HoldingRegister<UInt32>(41238)] private UInt32 _electricMeterCPhaseActivePower; // 0xA116
// ───────────────────────────────────────────────
// Battery Cabinet 1 — Energy / Pack measurements (read-only)
// ───────────────────────────────────────────────
[HoldingRegister<UInt32>(45308)] private UInt32 _batteryCab1TotalChargingEnergy; // 0xB0FC kW·h
[HoldingRegister<UInt32>(45310)] private UInt32 _batteryCab1TotalDischargedEnergy; // 0xB0FE kW·h
[HoldingRegister<UInt32>(45312)] private UInt32 _batteryCab1PackTotalVoltage; // 0xB100 (resolution 0.01 V)
[HoldingRegister<UInt32>(45314)] private UInt32 _batteryCab1PackTotalCurrent; // 0xB102 (resolution 0.01 A)
[HoldingRegister<UInt32>(45316)] private UInt32 _batteryCab1Temperature; // 0xB104 (resolution 0.01 °C)
[HoldingRegister<UInt32>(45318)] private UInt32 _batteryCab1Soc; // 0xB106 %
[HoldingRegister<UInt32>(45320)] private UInt32 _batteryCab1Soh; // 0xB108 %
// ───────────────────────────────────────────────
// Battery Cabinet 2 — Energy / Pack Measurements (Read-Only)
// ───────────────────────────────────────────────
[HoldingRegister<UInt32>(45564)] private UInt32 _batteryCab2TotalChargingEnergy; // 0xB1FC kW·h
[HoldingRegister<UInt32>(45566)] private UInt32 _batteryCab2TotalDischargedEnergy; // 0xB1FE kW·h
[HoldingRegister<UInt32>(45568)] private UInt32 _batteryCab2PackTotalVoltage; // 0xB200 (0.01 V)
[HoldingRegister<UInt32>(45570)] private UInt32 _batteryCab2PackTotalCurrent; // 0xB202 (0.01 A)
[HoldingRegister<UInt32>(45572)] private UInt32 _batteryCab2Temperature; // 0xB204 (0.01 °C)
[HoldingRegister<UInt32>(45574)] private UInt32 _batteryCab2Soc; // 0xB206 %
[HoldingRegister<UInt32>(45576)] private UInt32 _batteryCab2Soh; // 0xB208 %
// ───────────────────────────────────────────────
// Time-based scheduling (period 1) configuration
// ───────────────────────────────────────────────
//[HoldingRegister<UInt32>(49328, writable: true)] private UInt32 _Timed_Charge_and_Discharge_Off; // 0xC0B4, bit flags SunSat
//[HoldingRegister<UInt32>(49330, writable: true)] private UInt32 _Other_time_period_mode; // 0xC0B4, bit flags SunSat
[HoldingRegister<UInt32>(49332, writable: true)] private UInt32 _repetitiveWeeks; // 0xC0B4, bit flags SunSat
[HoldingRegister<UInt32>(49334, writable: true)] private UInt32 _effectiveStartDate; // 0xC0B6, UNIX timestamp (UTC+offset)
[HoldingRegister<UInt32>(49336, writable: true)] private UInt32 _effectiveEndDate; // 0xC0B8, UNIX timestamp (UTC+offset)
[HoldingRegister<UInt32>(49338, writable: true)] private UInt32 _chargingPowerPeriod1; // 0xC0BA, float [050] kW, default 5
[HoldingRegister<UInt32>(49340, writable: true)] private UInt32 _dischargingPowerPeriod1; // 0xC0BA, float [050] kW, default 5
// ───────────────────────────────────────────────
// Time-based charge/discharge schedule period 1
// ───────────────────────────────────────────────
[HoldingRegister<UInt32>(49172, writable: true)] private UInt32 _chargeStartTimePeriod1; // 0xC014 [0-2359] (start)
[HoldingRegister<UInt32>(49174, writable: true)] private UInt32 _chargeEndTimePeriod1; // 0xC016 [0-2359] (end)
[HoldingRegister<UInt32>(49176, writable: true)] private UInt32 _dischargeStartTimePeriod1; // 0xC018 [0-2359] (start)
[HoldingRegister<UInt32>(49178, writable: true)] private UInt32 _dischargeEndTimePeriod1; // 0xC01A [0-2359] (end)
}