853 lines
32 KiB
C#
853 lines
32 KiB
C#
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
|
||
{
|
||
/// <summary>
|
||
/// 系统配置服务中心
|
||
/// </summary>
|
||
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<PeakValleyConfig>().ToList();
|
||
//削峰填谷模式的时间监视线程
|
||
var ListenPeakValleyTimeTaskInfo = Task.Run(() => ListenPeakValleyTimeCycle());
|
||
|
||
//加载控制参数配置
|
||
LoadControlConfigValue();
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 储能运行配置值
|
||
/// </summary>
|
||
public EnergyStorageRunConfig energyStorageRunConfig { get; set; }
|
||
|
||
/// <summary>
|
||
/// FreeSQL实例
|
||
/// </summary>
|
||
public IFreeSql FreeSql { get; }
|
||
public ILogService LogService { get; }
|
||
|
||
/// <summary>
|
||
/// 事件聚合器
|
||
/// </summary>
|
||
private readonly IEventAggregator _eventAggregator;
|
||
|
||
#region 系统参数配置
|
||
|
||
/// <summary>
|
||
/// 是否保存数据信息
|
||
/// </summary>
|
||
public bool IsSaveDataLog { get; set; } = true;
|
||
|
||
/// <summary>
|
||
/// BMS IP
|
||
/// </summary>
|
||
public string BMSIP { get; set; }
|
||
|
||
/// <summary>
|
||
/// BMS IP
|
||
/// </summary>
|
||
public string PCSIP { get; set; }
|
||
|
||
/// <summary>
|
||
/// 是否调试
|
||
/// 默认False
|
||
/// </summary>
|
||
public bool IsDebug { get; set; }
|
||
|
||
/// <summary>
|
||
/// 是不是Demo
|
||
/// 默认False
|
||
/// </summary>
|
||
public bool IsDemo { get; set; }
|
||
|
||
private bool _IsStartAuto = true;
|
||
/// <summary>
|
||
/// 在程序运行的初始状态时是否进行开始模式
|
||
/// 默认值为True
|
||
/// </summary>
|
||
public bool IsStartAuto
|
||
{
|
||
get { return _IsStartAuto; }
|
||
set { _IsStartAuto = value; RaisePropertyChanged(); }
|
||
}
|
||
|
||
|
||
|
||
#endregion
|
||
|
||
#region Mqtt Server配置参数
|
||
|
||
/// <summary>
|
||
/// MqttServerUrl
|
||
/// </summary>
|
||
public string MqttServerUrl { get; set; }
|
||
|
||
/// <summary>
|
||
/// MqttUser
|
||
/// </summary>
|
||
public string MqttUser { get; set; }
|
||
|
||
/// <summary>
|
||
/// MqttPwd
|
||
/// </summary>
|
||
public string MqttPwd { get; set; }
|
||
|
||
/// <summary>
|
||
/// MqttTopic
|
||
/// </summary>
|
||
public string MqttTopic { get; set; }
|
||
|
||
/// <summary>
|
||
/// MqttServerPort
|
||
/// </summary>
|
||
public int MqttServerPort { get; set; }
|
||
|
||
/// <summary>
|
||
/// MqttClientId
|
||
/// </summary>
|
||
public string MqttClientId { get; set; }
|
||
|
||
// MqttServerPort MqttClientId
|
||
#endregion
|
||
|
||
#region PCS配置参数
|
||
|
||
private double _PcsChangeValue;
|
||
/// <summary>
|
||
/// PCS的变化时的阈值设置
|
||
/// </summary>
|
||
public double PcsChangeValue
|
||
{
|
||
get { return _PcsChangeValue; }
|
||
set { _PcsChangeValue = value; }
|
||
}
|
||
|
||
|
||
#endregion
|
||
|
||
private double _TransformerCapacity;
|
||
/// <summary>
|
||
/// 变压器容量设置
|
||
/// </summary>
|
||
public double TransformerCapacity
|
||
{
|
||
get { return _TransformerCapacity; }
|
||
set { _TransformerCapacity = value; }
|
||
}
|
||
|
||
|
||
#region 削峰填谷配置
|
||
|
||
|
||
/// <summary>
|
||
/// 月浦特殊的削峰填谷的模型
|
||
/// </summary>
|
||
public SpecialPeakValley YuPuSpecialPeakValley { get; set; }
|
||
|
||
/// <summary>
|
||
/// 线程使能
|
||
/// </summary>
|
||
public bool ThreadEnable { get; set; } = true;
|
||
|
||
/// <summary>
|
||
/// 当前的削峰填谷的配置
|
||
/// 在配置服务中,供统计服务使用
|
||
/// </summary>
|
||
public PeakValleyConfig CurPeakValleyConfig { get; set; } = new PeakValleyConfig();
|
||
|
||
/// <summary>
|
||
/// 监听削峰填谷时间信息
|
||
/// 这个不管是否处于削峰填谷的时期都可以实时轮训获取
|
||
/// 那么当软件处于启动时就可以实时轮训
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private async Task ListenPeakValleyTimeCycle()
|
||
{
|
||
while (ThreadEnable)
|
||
{
|
||
//退出 由Master发送充放电的数据
|
||
if (!IsMaster) break;
|
||
try
|
||
{
|
||
|
||
//CurPeakValleyConfig = YuPuSpecialPeakValley.GetSpecialPeakValley();
|
||
_eventAggregator.GetEvent<PeakValleyTimeEvent>().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<PeakValleyTimeEvent>().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}");
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断时间是否在 某一时间段内
|
||
/// </summary>
|
||
/// <param name="timeStr"></param>
|
||
/// <returns></returns>
|
||
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;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 储能柜的削峰填谷的配置数据集
|
||
/// </summary>
|
||
public List<PeakValleyConfig> ListEnergyStoragePeakValleyTimeConfig { get; set; }
|
||
|
||
/// <summary>
|
||
/// 电表动作的上限和下限值
|
||
///维持电表在一个区间而不是一个具体的值
|
||
///相当于回差值的意思,防止维持在一个点反复的波动导致问题
|
||
/// </summary>
|
||
public EleMeterActionValue EMSActionLimitValue { get; set; } = new EleMeterActionValue()
|
||
{
|
||
UpValue = 15,
|
||
//MidValue = 7,
|
||
DownValue = 8,
|
||
TargetValue = 12
|
||
};
|
||
|
||
#endregion
|
||
|
||
|
||
#region MasterSlave分布通信参数
|
||
|
||
/// <summary>
|
||
/// 是否是主站
|
||
/// </summary>
|
||
public bool IsMaster { get; set; }
|
||
|
||
/// <summary>
|
||
/// Client连接Server的Url
|
||
/// </summary>
|
||
public string ServerUrl { get; set; }
|
||
|
||
/// <summary>
|
||
/// 站信息数据
|
||
/// </summary>
|
||
public ushort Station { get; set; }
|
||
|
||
#endregion
|
||
|
||
#region 液冷设置参数
|
||
|
||
/// <summary>
|
||
/// 制热设定温度
|
||
/// </summary>
|
||
public int SetHeadTargetTemp { get; set; } = 25;
|
||
|
||
/// <summary>
|
||
/// 制冷设定温度
|
||
/// </summary>
|
||
public int SetCoolTargetTemp { get; set; } = 25;
|
||
|
||
/// <summary>
|
||
/// 控制模式
|
||
/// 0 停止
|
||
/// 1 制冷
|
||
/// 2 制热
|
||
/// 3 自循环
|
||
/// 4 自动
|
||
/// </summary>
|
||
public int SetCtrModel { get; set; } = 4;
|
||
|
||
|
||
#endregion
|
||
|
||
|
||
#region 数据保存的配置
|
||
|
||
/// <summary>
|
||
/// 数据保存的地址信息
|
||
/// </summary>
|
||
public string DataLogFile { get; set; } = string.Empty;
|
||
|
||
#endregion
|
||
|
||
|
||
#region 控制参数配置
|
||
|
||
/// <summary>
|
||
/// 控制参数配置文件路径
|
||
/// </summary>
|
||
private readonly string _controlConfigFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config", "ControlConfigValue.json");
|
||
|
||
/// <summary>
|
||
/// 控制参数配置值
|
||
/// </summary>
|
||
public ControlConfigValue ControlConfigValue { get; set; }
|
||
|
||
/// <summary>
|
||
/// 加载控制参数配置
|
||
/// </summary>
|
||
/// <returns>返回加载结果,true表示成功,false表示失败</returns>
|
||
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<ControlConfigValue>(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<DisChargeModelItem>();
|
||
}
|
||
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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 保存控制参数配置
|
||
/// </summary>
|
||
/// <returns>返回保存结果,true表示成功,false表示失败</returns>
|
||
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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新控制参数配置的值并保存
|
||
/// </summary>
|
||
/// <param name="configValue">要更新的控制参数配置对象</param>
|
||
/// <returns>返回更新结果,true表示成功,false表示失败</returns>
|
||
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;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取放电时间配置集合
|
||
/// </summary>
|
||
/// <returns>放电时间配置列表(永不返回 null)</returns>
|
||
public List<DisChargeModelItem> GetDisChargeModel()
|
||
{
|
||
if (ControlConfigValue == null)
|
||
{
|
||
ControlConfigValue = new ControlConfigValue();
|
||
}
|
||
|
||
if (ControlConfigValue.DisChargeModel == null)
|
||
{
|
||
ControlConfigValue.DisChargeModel = new List<DisChargeModelItem>();
|
||
}
|
||
|
||
return ControlConfigValue.DisChargeModel;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 保存放电时间配置集合
|
||
/// </summary>
|
||
/// <param name="items">放电时间配置列表</param>
|
||
/// <returns>保存结果</returns>
|
||
public bool SaveDisChargeModel(List<DisChargeModelItem> items)
|
||
{
|
||
if (ControlConfigValue == null)
|
||
{
|
||
ControlConfigValue = new ControlConfigValue();
|
||
}
|
||
|
||
// 基础校验
|
||
var list = items ?? new List<DisChargeModelItem>();
|
||
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();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 时间上是否可以放电
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
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
|
||
|
||
}
|
||
}
|