diff --git a/csharp/App/SinexcelCommunication/Program.cs b/csharp/App/SinexcelCommunication/Program.cs index 3bfb7cca0..26b210dd4 100644 --- a/csharp/App/SinexcelCommunication/Program.cs +++ b/csharp/App/SinexcelCommunication/Program.cs @@ -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; @@ -117,13 +119,48 @@ internal static class Program var statusrecord = ReadStatus(); if (statusrecord == null) return null; + + // 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 "); + + 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); 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 - //if (statusrecord?.InverterRecord != null) sinexcelDevice.Write(statusrecord.InverterRecord); + + 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 ")+ "run iteration time finish"); @@ -247,10 +284,11 @@ internal static class Program var modbusData = new Dictionary(); // SYSTEM DATA - var result1 = ConvertToModbusRegisters((status.Config.MinSoc * 10), "UInt16", 30001); // this to be updated to modbusTCP version - var result2 = ConvertToModbusRegisters(status.InverterRecord.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 @@ -274,39 +312,66 @@ internal static class Program return true; } - private static Dictionary ConvertToModbusRegisters(Object value, String outputType, Int32 startingAddress) + private static Dictionary ConvertToModbusRegisters(object value, string outputType, int startingAddress) { - var registers = new Dictionary(); + var regs = new Dictionary(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 DataLogging(StatusRecord status, DateTime timeStamp) {