using HslCommunication.MQTT; using OrpaonEMS.App.Com; using OrpaonEMS.App.Models; using OrpaonEMS.App.PrismEvent; using OrpaonEMS.Core; using OrpaonEMS.Core.Enums; using OrpaonEMS.Model; using OrpaonEMS.Model.Enums; using Prism.Events; using Prism.Mvvm; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Text.Json; using System.Threading.Tasks; using System.Windows.Documents; namespace OrpaonEMS.App.Services { /// /// 系统配置服务中心 /// public class ConfigDataService : BindableBase { public ConfigDataService(IFreeSql freeSql, ILogService logService, IEventAggregator eventAggregator) { FreeSql = freeSql; LogService = logService; _eventAggregator = eventAggregator; //储能运行配置值的实例化-初始值 energyStorageRunConfig = new EnergyStorageRunConfig(); energyStorageRunConfig.PcsChargOffset = double.Parse(ConfigHelper.GetValue("PcsChargOffset")); energyStorageRunConfig.PcsDisChargOffset = double.Parse(ConfigHelper.GetValue("PcsDisChargOffset")); energyStorageRunConfig.MaxBatChargRatio = double.Parse(ConfigHelper.GetValue("MaxBatChargRatio")); energyStorageRunConfig.MaxBatDisChargRatio = double.Parse(ConfigHelper.GetValue("MaxBatDisChargRatio")); energyStorageRunConfig.BMSSocUpSignLimitValue = double.Parse(ConfigHelper.GetValue("BMSSocUpSignLimitValue")); energyStorageRunConfig.BMSSocDownSignLimitValue = double.Parse(ConfigHelper.GetValue("BMSSocDownSignLimitValue")); IsMaster = ConfigHelper.GetValue("IsMaster") == "1" ? true : false; ServerUrl = ConfigHelper.GetValue("ServerUrl"); Station = ushort.Parse(ConfigHelper.GetValue("Station")); BMSIP = ConfigHelper.GetValue("BMSIP"); PCSIP = ConfigHelper.GetValue("PCSIP"); IsDebug = ConfigHelper.GetValue("IsDebug") == "True" ? true : false; IsDemo = ConfigHelper.GetValue("IsDemo") == "True" ? true : false; EMSActionLimitValue.TargetValue = double.Parse(ConfigHelper.GetValue("ControlTargetValue")); PcsChangeValue = double.Parse(ConfigHelper.GetValue("PcsChangeValue")); MqttServerUrl = ConfigHelper.GetValue("MqttServerUrl"); MqttTopic = ConfigHelper.GetValue("MqttTopic");//v1/devices/me/telemetry MqttServerPort = int.Parse(ConfigHelper.GetValue("MqttServerPort")); MqttClientId = ConfigHelper.GetValue("MqttClientId"); MqttUser = ConfigHelper.GetValue("MqttUser"); MqttPwd = ConfigHelper.GetValue("MqttPwd"); //数据保存的配置信息 DataLogFile = ConfigHelper.GetValue("DataLogFile"); YuPuSpecialPeakValley = new SpecialPeakValley(); //获取配置信息 ListEnergyStoragePeakValleyTimeConfig = FreeSql.Select().ToList(); //削峰填谷模式的时间监视线程 var ListenPeakValleyTimeTaskInfo = Task.Run(() => ListenPeakValleyTimeCycle()); //加载控制参数配置 LoadControlConfigValue(); } /// /// 储能运行配置值 /// public EnergyStorageRunConfig energyStorageRunConfig { get; set; } /// /// FreeSQL实例 /// public IFreeSql FreeSql { get; } public ILogService LogService { get; } /// /// 事件聚合器 /// private readonly IEventAggregator _eventAggregator; #region 系统参数配置 /// /// 是否保存数据信息 /// public bool IsSaveDataLog { get; set; } = true; /// /// BMS IP /// public string BMSIP { get; set; } /// /// BMS IP /// public string PCSIP { get; set; } /// /// 是否调试 /// 默认False /// public bool IsDebug { get; set; } /// /// 是不是Demo /// 默认False /// public bool IsDemo { get; set; } private bool _IsStartAuto = true; /// /// 在程序运行的初始状态时是否进行开始模式 /// 默认值为True /// public bool IsStartAuto { get { return _IsStartAuto; } set { _IsStartAuto = value; RaisePropertyChanged(); } } #endregion #region Mqtt Server配置参数 /// /// MqttServerUrl /// public string MqttServerUrl { get; set; } /// /// MqttUser /// public string MqttUser { get; set; } /// /// MqttPwd /// public string MqttPwd { get; set; } /// /// MqttTopic /// public string MqttTopic { get; set; } /// /// MqttServerPort /// public int MqttServerPort { get; set; } /// /// MqttClientId /// public string MqttClientId { get; set; } // MqttServerPort MqttClientId #endregion #region PCS配置参数 private double _PcsChangeValue; /// /// PCS的变化时的阈值设置 /// public double PcsChangeValue { get { return _PcsChangeValue; } set { _PcsChangeValue = value; } } #endregion private double _TransformerCapacity; /// /// 变压器容量设置 /// public double TransformerCapacity { get { return _TransformerCapacity; } set { _TransformerCapacity = value; } } #region 削峰填谷配置 /// /// 月浦特殊的削峰填谷的模型 /// public SpecialPeakValley YuPuSpecialPeakValley { get; set; } /// /// 线程使能 /// public bool ThreadEnable { get; set; } = true; /// /// 当前的削峰填谷的配置 /// 在配置服务中,供统计服务使用 /// public PeakValleyConfig CurPeakValleyConfig { get; set; } = new PeakValleyConfig(); /// /// 监听削峰填谷时间信息 /// 这个不管是否处于削峰填谷的时期都可以实时轮训获取 /// 那么当软件处于启动时就可以实时轮训 /// /// private async Task ListenPeakValleyTimeCycle() { while (ThreadEnable) { //退出 由Master发送充放电的数据 if (!IsMaster) break; try { //CurPeakValleyConfig = YuPuSpecialPeakValley.GetSpecialPeakValley(); _eventAggregator.GetEvent().Publish(YuPuSpecialPeakValley.GetSpecialPeakValley()); var TimeInfo = DateTime.Now.ToString("HH:mm"); foreach (var item in ListEnergyStoragePeakValleyTimeConfig) { if (item.Enable) { if (GetIsTimeSpan(TimeInfo, item.StartTime, item.EndTime)) { CurPeakValleyConfig = item; //_eventAggregator.GetEvent().Publish(item.ElePV); //PeakValleySglModel = item.ElePV; //switch (item.ElePV) //{ // case ElePVEnum.Peak: // EsSysPeakVellayStateMsg = "峰价"; // break; // case ElePVEnum.Valley: // EsSysPeakVellayStateMsg = "谷价"; // break; // case ElePVEnum.Flat: // EsSysPeakVellayStateMsg = "平价"; // break; // default: // break; //} break; } } } await Task.Delay(10000); //使用这个线程 //mqttClientDrive.mqttEntity.PcsPower = InPowerPCSDataService.Power; //mqttClientDrive.mqttEntity.PcsTotalReactivePw = InPowerPCSDataService.TotalReactivePw; //mqttClientDrive.mqttEntity.PcsTotalApparentPw = InPowerPCSDataService.TotalApparentPw; //mqttClientDrive.mqttEntity.PcsInputVol = InPowerPCSDataService.InputVol; //mqttClientDrive.mqttEntity.PcsInputCur = InPowerPCSDataService.InputCur; //mqttClientDrive.mqttEntity.PcsInputPw = InPowerPCSDataService.InputPw; //mqttClientDrive.mqttEntity.PcsCurAlarmStateStr = InPowerPCSDataService.CurPCSAlarmStateStr; //mqttClientDrive.mqttEntity.PcsAVol = InPowerPCSDataService.AVol; //mqttClientDrive.mqttEntity.PcsBVol = InPowerPCSDataService.BVol; //mqttClientDrive.mqttEntity.PcsCVol = InPowerPCSDataService.CVol; //mqttClientDrive.mqttEntity.PcsACur = InPowerPCSDataService.ACur; //mqttClientDrive.mqttEntity.PcsBCur = InPowerPCSDataService.BCur; //mqttClientDrive.mqttEntity.PcsCCur = InPowerPCSDataService.CCur; //mqttClientDrive.mqttEntity.PCSFaultStateStr = InPowerPCSDataService.CurPCSFaultStateStr; //mqttClientDrive.mqttEntity.BmsCur = BmsDataService.BmsCur.RtValue; //mqttClientDrive.mqttEntity.BmsVol = BmsDataService.BmsVol.RtValue; //mqttClientDrive.mqttEntity.BmsSOC = BmsDataService.BmsSOC.RtValue; //mqttClientDrive.mqttEntity.BmsSOH = BmsDataService.BmsSOH.RtValue; //mqttClientDrive.mqttEntity.BmsSOE = BmsDataService.BmsSOE.RtValue; //mqttClientDrive.mqttEntity.BmsResP = BmsDataService.BmsResP.RtValue; //mqttClientDrive.mqttEntity.BmsResN = BmsDataService.BmsResN.RtValue; //mqttClientDrive.mqttEntity.BmsAccCharg = BmsDataService.BmsAccCharg.RtValue; //mqttClientDrive.mqttEntity.BmsAccDisCharg = BmsDataService.BmsAccDisCharg.RtValue; //mqttClientDrive.mqttEntity.BmsPw = 0; //mqttClientDrive.mqttEntity.BmsBatState = BmsDataService.BmsBatState; //mqttClientDrive.mqttEntity.MaxChargePowerCell = BmsDataService.MaxChargePowerCell.RtValue; //mqttClientDrive.mqttEntity.MaxDisChargePowerCell = BmsDataService.MaxDisChargePowerCell.RtValue; //mqttClientDrive.mqttEntity.InPress = BmsDataService.InPress.RtValue; //mqttClientDrive.mqttEntity.OutPress = BmsDataService.OutPress.RtValue; //mqttClientDrive.mqttEntity.OutTemp = BmsDataService.OutTemp.RtValue; //mqttClientDrive.mqttEntity.InTemp = BmsDataService.InTemp.RtValue; //mqttClientDrive.mqttEntity.CoolFaultCode = BmsDataService.CoolFaultCode; //mqttClientDrive.mqttEntity.CoolStates = BmsDataService.CoolStates; //mqttClientDrive.mqttEntity.FireSmokeTrig = BmsDataService.FireSmokeTrig; //mqttClientDrive.mqttEntity.FireTempTrig = BmsDataService.FireTempTrig; //mqttClientDrive.mqttEntity.FireMainPowerState = BmsDataService.FireMainPowerState; } catch (Exception ex) { LogService.Info($"时间:{DateTime.Now.ToString()}-【ListenPeakValleyTimeCycle】-{ex.Message}"); } } } /// /// 判断时间是否在 某一时间段内 /// /// /// public bool GetIsTimeSpan(string timeStr, string startTime, string endTime) { //判断当前时间是否在工作时间段内 //string _strWorkingDayAM = "08:30";//工作时间上午08:30 //string _strWorkingDayPM = "17:30"; TimeSpan dspStart = DateTime.Parse(startTime).TimeOfDay; TimeSpan dspEnd = DateTime.Parse(endTime).TimeOfDay; //string time1 = "2017-2-17 8:10:00"; DateTime t1 = Convert.ToDateTime(timeStr); TimeSpan dspNow = t1.TimeOfDay; if (dspNow > dspStart && dspNow < dspEnd) { return true; } else if (dspStart > dspEnd)//时间区间处于跨天的状态 { if (dspNow >= dspStart || dspNow <= dspEnd) { return true; } } return false; } /// /// 储能柜的削峰填谷的配置数据集 /// public List ListEnergyStoragePeakValleyTimeConfig { get; set; } /// /// 电表动作的上限和下限值 ///维持电表在一个区间而不是一个具体的值 ///相当于回差值的意思,防止维持在一个点反复的波动导致问题 /// public EleMeterActionValue EMSActionLimitValue { get; set; } = new EleMeterActionValue() { UpValue = 15, //MidValue = 7, DownValue = 8, TargetValue = 12 }; #endregion #region MasterSlave分布通信参数 /// /// 是否是主站 /// public bool IsMaster { get; set; } /// /// Client连接Server的Url /// public string ServerUrl { get; set; } /// /// 站信息数据 /// public ushort Station { get; set; } #endregion #region 液冷设置参数 /// /// 制热设定温度 /// public int SetHeadTargetTemp { get; set; } = 25; /// /// 制冷设定温度 /// public int SetCoolTargetTemp { get; set; } = 25; /// /// 控制模式 /// 0 停止 /// 1 制冷 /// 2 制热 /// 3 自循环 /// 4 自动 /// public int SetCtrModel { get; set; } = 4; #endregion #region 数据保存的配置 /// /// 数据保存的地址信息 /// public string DataLogFile { get; set; } = string.Empty; #endregion #region 控制参数配置 /// /// 控制参数配置文件路径 /// private readonly string _controlConfigFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config", "ControlConfigValue.json"); /// /// 控制参数配置值 /// public ControlConfigValue ControlConfigValue { get; set; } /// /// 加载控制参数配置 /// /// 返回加载结果,true表示成功,false表示失败 public bool LoadControlConfigValue() { try { // 确保目录存在 string directory = Path.GetDirectoryName(_controlConfigFilePath); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); LogService.Info($"创建配置目录: {directory}"); } // 检查文件是否存在 if (File.Exists(_controlConfigFilePath)) { // 读取JSON文件内容 string jsonContent = File.ReadAllText(_controlConfigFilePath, Encoding.UTF8); // 检查文件是否为空或只包含空对象 if (string.IsNullOrWhiteSpace(jsonContent) || jsonContent.Trim() == "{}" || jsonContent.Trim() == "{\r\n \r\n}") { // 文件为空,创建默认配置 LogService.Info("控制参数配置文件为空,创建默认配置"); ControlConfigValue = new ControlConfigValue(); SaveControlConfigValue(); } else { // 反序列化JSON到对象 var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, WriteIndented = true, Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; ControlConfigValue = JsonSerializer.Deserialize(jsonContent, options); // 验证反序列化结果 if (ControlConfigValue == null) { LogService.Warn("控制参数配置反序列化失败,使用默认配置"); ControlConfigValue = new ControlConfigValue(); SaveControlConfigValue(); } else { LogService.Info("成功加载控制参数配置"); // 兼容键名末尾带空格的 SelectedDisChargeModel try { using (var doc = JsonDocument.Parse(jsonContent)) { var root = doc.RootElement; if (root.TryGetProperty("SelectedDisChargeModel ", out var selectedProp)) { if (selectedProp.ValueKind == JsonValueKind.Number) { ControlConfigValue.SelectedDisChargeModel = selectedProp.GetInt32(); } else if (selectedProp.ValueKind == JsonValueKind.String && int.TryParse(selectedProp.GetString(), out var selInt)) { ControlConfigValue.SelectedDisChargeModel = selInt; } } } } catch (Exception ex) { LogService.Warn($"SelectedDisChargeModel(带空格) 兼容解析失败: {ex.Message}"); } } } } else { // 文件不存在,创建默认配置 LogService.Info($"控制参数配置文件不存在,创建默认配置: {_controlConfigFilePath}"); ControlConfigValue = new ControlConfigValue(); SaveControlConfigValue(); } // 兼容旧配置:确保 DisChargeModel 非空,并在为空列表时注入默认项 if (ControlConfigValue != null) { if (ControlConfigValue.DisChargeModel == null) { ControlConfigValue.DisChargeModel = new List(); } if (ControlConfigValue.DisChargeModel.Count == 0) { ControlConfigValue.DisChargeModel.Add(new DisChargeModelItem { Model = 1, DisChargeTime = "08:00" }); ControlConfigValue.DisChargeModel.Add(new DisChargeModelItem { Model = 2, DisChargeTime = "11:00" }); if (ControlConfigValue.SelectedDisChargeModel <= 0) { ControlConfigValue.SelectedDisChargeModel = 1; } // 保存注入的默认配置 SaveControlConfigValue(); } } return true; } catch (JsonException jsonEx) { // JSON解析错误 LogService.Error($"控制参数配置JSON解析错误: {jsonEx.Message}"); LogService.Error($"异常堆栈: {jsonEx.StackTrace}"); // 使用默认配置 ControlConfigValue = new ControlConfigValue(); // 尝试备份损坏的文件 try { if (File.Exists(_controlConfigFilePath)) { string backupPath = $"{_controlConfigFilePath}.backup_{DateTime.Now:yyyyMMddHHmmss}"; File.Copy(_controlConfigFilePath, backupPath, true); LogService.Info($"已备份损坏的配置文件到: {backupPath}"); } } catch (Exception backupEx) { LogService.Error($"备份损坏的配置文件失败: {backupEx.Message}"); } // 保存默认配置 SaveControlConfigValue(); return false; } catch (Exception ex) { // 其他异常 LogService.Error($"加载控制参数配置时发生异常: {ex.Message}"); LogService.Error($"异常类型: {ex.GetType().Name}"); LogService.Error($"异常堆栈: {ex.StackTrace}"); // 使用默认配置 ControlConfigValue = new ControlConfigValue(); return false; } } /// /// 保存控制参数配置 /// /// 返回保存结果,true表示成功,false表示失败 public bool SaveControlConfigValue() { try { // 验证配置对象 if (ControlConfigValue == null) { LogService.Error("控制参数配置对象为空,无法保存"); return false; } // 确保目录存在 string directory = Path.GetDirectoryName(_controlConfigFilePath); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); LogService.Info($"创建配置目录: {directory}"); } // 序列化对象到JSON var options = new JsonSerializerOptions { WriteIndented = true, Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; string jsonContent = JsonSerializer.Serialize(ControlConfigValue, options); // 写入文件前先写入临时文件 string tempFilePath = $"{_controlConfigFilePath}.tmp"; File.WriteAllText(tempFilePath, jsonContent, Encoding.UTF8); // 验证临时文件是否写入成功 if (File.Exists(tempFilePath)) { // 备份原文件(如果存在) if (File.Exists(_controlConfigFilePath)) { string backupPath = $"{_controlConfigFilePath}.bak"; File.Copy(_controlConfigFilePath, backupPath, true); } // 用临时文件替换原文件 File.Copy(tempFilePath, _controlConfigFilePath, true); File.Delete(tempFilePath); LogService.Info($"成功保存控制参数配置到: {_controlConfigFilePath}"); return true; } else { LogService.Error("临时配置文件写入失败"); return false; } } catch (IOException ioEx) { // 文件IO异常 LogService.Error($"保存控制参数配置时发生IO异常: {ioEx.Message}"); LogService.Error($"异常堆栈: {ioEx.StackTrace}"); return false; } catch (JsonException jsonEx) { // JSON序列化异常 LogService.Error($"控制参数配置JSON序列化错误: {jsonEx.Message}"); LogService.Error($"异常堆栈: {jsonEx.StackTrace}"); return false; } catch (Exception ex) { // 其他异常 LogService.Error($"保存控制参数配置时发生异常: {ex.Message}"); LogService.Error($"异常类型: {ex.GetType().Name}"); LogService.Error($"异常堆栈: {ex.StackTrace}"); return false; } } /// /// 更新控制参数配置的值并保存 /// /// 要更新的控制参数配置对象 /// 返回更新结果,true表示成功,false表示失败 public bool UpdateControlConfigValue(ControlConfigValue configValue) { try { if (configValue == null) { LogService.Error("传入的控制参数配置对象为空"); return false; } // 更新配置值 ControlConfigValue.SolarToEsAsFullSoc = configValue.SolarToEsAsFullSoc; ControlConfigValue.Master_ToSlaveByMasterSoc = configValue.Master_ToSlaveByMasterSoc; ControlConfigValue.Master_ToSlaveBySlaveSoc = configValue.Master_ToSlaveBySlaveSoc; ControlConfigValue.Master_SolarToSlaveEsFullByMasterSoc = configValue.Master_SolarToSlaveEsFullByMasterSoc; ControlConfigValue.Slave_ToMasterBySlaveSoc = configValue.Slave_ToMasterBySlaveSoc; ControlConfigValue.Slave_ToMasterByMasterSoc = configValue.Slave_ToMasterByMasterSoc; ControlConfigValue.Slave_SolarToMasterEsFullBySlaverSoc = configValue.Slave_SolarToMasterEsFullBySlaverSoc; ControlConfigValue.NightMaster_ToMasterFullSoc = configValue.NightMaster_ToMasterFullSoc; ControlConfigValue.NightSlave_ToSlaveFullSoc = configValue.NightSlave_ToSlaveFullSoc; // 保存到文件 bool saveResult = SaveControlConfigValue(); if (saveResult) { LogService.Info("成功更新并保存控制参数配置"); } else { LogService.Error("更新控制参数配置后保存失败"); } return saveResult; } catch (Exception ex) { LogService.Error($"更新控制参数配置时发生异常: {ex.Message}"); LogService.Error($"异常堆栈: {ex.StackTrace}"); return false; } } /// /// 获取放电时间配置集合 /// /// 放电时间配置列表(永不返回 null) public List GetDisChargeModel() { if (ControlConfigValue == null) { ControlConfigValue = new ControlConfigValue(); } if (ControlConfigValue.DisChargeModel == null) { ControlConfigValue.DisChargeModel = new List(); } return ControlConfigValue.DisChargeModel; } /// /// 保存放电时间配置集合 /// /// 放电时间配置列表 /// 保存结果 public bool SaveDisChargeModel(List items) { if (ControlConfigValue == null) { ControlConfigValue = new ControlConfigValue(); } // 基础校验 var list = items ?? new List(); foreach (var it in list) { if (it == null) { LogService.Error("DisChargeModel 中存在空项"); return false; } if (string.IsNullOrWhiteSpace(it.DisChargeTime)) { LogService.Error("DisChargeModel.DisChargeTime 为空"); return false; } if (!TimeSpan.TryParse(it.DisChargeTime, out _)) { LogService.Error($"DisChargeModel.DisChargeTime 格式非法: {it.DisChargeTime},期望 HH:mm"); return false; } } ControlConfigValue.DisChargeModel = list; return SaveControlConfigValue(); } /// /// 时间上是否可以放电 /// /// public bool IsTimeCanDischarge() { try { // 确保配置加载 if (ControlConfigValue == null) { LoadControlConfigValue(); } // 获取放电时间集合(内部已保证非 null) var list = GetDisChargeModel(); // 选中模式 Id(缺省=1) int selectedId = 1; try { selectedId = ControlConfigValue?.SelectedDisChargeModel ?? 1; } catch { selectedId = 1; } // 查找选中项,找不到回退第一项 DisChargeModelItem selected = null; if (list != null && list.Count > 0) { foreach (var it in list) { if (it != null && it.Model == selectedId) { selected = it; break; } } if (selected == null) { selected = list[0]; } } // 解析时间(HH:mm),失败回退 08:00 TimeSpan target; if (selected != null && !string.IsNullOrWhiteSpace(selected.DisChargeTime) && TimeSpan.TryParse(selected.DisChargeTime, out target)) { return DateTime.Now.TimeOfDay >= target; } else { LogService.Warn("IsTimeCanDischarge: 配置时间缺失或格式非法,使用默认 08:00 进行比较"); target = new TimeSpan(8, 0, 0); return DateTime.Now.TimeOfDay >= target; } } catch (Exception ex) { LogService.Error($"IsTimeCanDischarge 执行失败: {ex.Message}"); return false; } } #endregion } }