using System.Diagnostics.CodeAnalysis; using System.Text.Json; using InnovEnergy.App.SinexcelCommunication.DataTypes; using InnovEnergy.Lib.Devices.Sinexcel_12K_TL.DataType; using InnovEnergy.Lib.Utils; using static System.Text.Json.JsonSerializer; namespace InnovEnergy.App.SinexcelCommunication.SystemConfig; [SuppressMessage("Trimming", "IL2026:Members annotated with \'RequiresUnreferencedCodeAttribute\' require dynamic access otherwise can break functionality when trimming application code")] public class Config { private static String DefaultConfigFilePath => Path.Combine(Environment.CurrentDirectory, "config.json"); private static DateTime DefaultDatetime => new(2025, 01, 01, 09, 00, 00); private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true }; public required DeviceConfig Devices { get; set; } //public required Boolean DynamicPricingEnabled { get; set; } //public required DynamicPricingMode DynamicPricingMode { get; set; } //public required Decimal CheapPrice { get; set; } //public required Decimal HighPrice { get; set; } 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 OperatingPriority OperatingPriority { get; set; } public required Int16 BatteriesCount { get; set; } public required Int16 ClusterNumber { get; set; } public required Int16 PvNumber { get; set; } public required Double ModbusProtcolNumber { get; set; } public required DateTime StartTimeChargeandDischargeDayandTime { get; set; } public required DateTime StopTimeChargeandDischargeDayandTime { get; set; } public required Single TimeChargeandDischargePower { get; set; } public required Boolean ControlPermission { get; set; } public required S3Config? S3 { get; set; } private static String? LastSavedData { get; set; } private static DateTime? LoadedWriteTimeUtc { get; set; } public static Config Default => new() { Devices = new () { Serial = new() {BaudRate = 115200, Parity = 0, StopBits = 1, DataBits = 8}, Inverter1 = new() {DeviceState = DeviceState.Measured, Port = "/dev/ttyUSB0", SlaveId = 1}, Inverter2 = new() {DeviceState = DeviceState.Measured, Port = "/dev/ttyUSB1", SlaveId = 1}, Inverter3 = new() {DeviceState = DeviceState.Measured, Port = "/dev/ttyUSB3", SlaveId = 1}, Inverter4 = new() {DeviceState = DeviceState.Measured, Port = "/dev/ttyUSB4", SlaveId = 1}, }, //DynamicPricingEnabled = false, //DynamicPricingMode = DynamicPricingMode.Disabled, MinSoc = 20, GridSetPoint = 0, MaximumChargingCurrent = 180, MaximumDischargingCurrent = 180, OperatingPriority = OperatingPriority.LoadPriority, BatteriesCount = 0, ClusterNumber = 0, PvNumber = 0, ModbusProtcolNumber = 1.2, StartTimeChargeandDischargeDayandTime = DefaultDatetime, StopTimeChargeandDischargeDayandTime = DefaultDatetime, TimeChargeandDischargePower = 3, ControlPermission = false, S3 = new() { Bucket = "1-3e5b3069-214a-43ee-8d85-57d72000c19d", Region = "sos-ch-dk-2", Provider = "exo.io", Key = "EXObb5a49acb1061781761895e7", Secret = "sKhln0w8ii3ezZ1SJFF33yeDo8NWR1V4w2H0D4-350I", ContentType = "text/plain; charset=utf-8" } }; public void Save(String? path = null) { var configFilePath = path ?? DefaultConfigFilePath; var currentWriteTime = File.GetLastWriteTimeUtc(configFilePath); if (currentWriteTime != LoadedWriteTimeUtc) throw new IOException("Config file changed on disk since it was loaded; refusing to overwrite."); // to prevent an overwriting while an external changes happended in the meantime try { var jsonString = Serialize(this, JsonOptions); if (LastSavedData == jsonString) return; LastSavedData = jsonString; File.WriteAllText(configFilePath, jsonString); } catch (Exception e) { $"Failed to write config file {configFilePath}\n{e}".WriteLine(); throw; } } /* public static Config Load(String? path = null) { var configFilePath = path ?? DefaultConfigFilePath; try { var jsonString = File.ReadAllText(configFilePath); // LoadedWriteTimeUtc = File.GetLastWriteTimeUtc(configFilePath); return Deserialize(jsonString)!; } catch (Exception e) { $"Failed to read config file {configFilePath}, using default config\n{e}".WriteLine(); return Default; } }*/ public static Config Load(string? path = null) { var configFilePath = path ?? DefaultConfigFilePath; // ✅ handle null first try { // Now safe to call any File/Path API var json = File.ReadAllText(configFilePath); var cfg = Deserialize(json, JsonOptions) ?? throw new InvalidOperationException("Config deserialized to null."); // Optional: store last write time / last saved json LoadedWriteTimeUtc = File.GetLastWriteTimeUtc(configFilePath); LastSavedData = Serialize(cfg, JsonOptions); // if you use the save-skip logic return cfg; } catch (Exception e) { $"Failed to read config file {configFilePath}\n{e}".WriteLine(); throw; } } public static async Task LoadAsync(String? path = null) { var configFilePath = path ?? DefaultConfigFilePath; try { var jsonString = await File.ReadAllTextAsync(configFilePath); return Deserialize(jsonString)!; } catch (Exception e) { Console.WriteLine($"Couldn't read config file {configFilePath}, using default config"); e.Message.WriteLine(); return Default; } } }