using Backend.Models; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Quartz; using Repository.BackendRepository.Interface; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using System.Xml; namespace Backend.Quartz.Jobs { /// /// 電錶歸檔,每小時執行,只執行小時歸檔 /// [DisallowConcurrentExecution] class ArchiveElectricMeterHourJob : IJob { private readonly ILogger logger; private readonly IBackgroundServiceRepository backgroundServiceRepository; private readonly ILogger loggers; public ArchiveElectricMeterHourJob( ILogger logger, IBackgroundServiceRepository backgroundServiceRepository, ILogger loggers) { this.logger = logger; this.backgroundServiceRepository = backgroundServiceRepository; this.loggers = loggers; } public async Task Execute(IJobExecutionContext context) { Task_Detail task_Detail = new Task_Detail(loggers, backgroundServiceRepository); try { if(await task_Detail.GetNeedWorkTask("ArchiveElectricMeterHourJob", "All")) { await task_Detail.InsertWorkTime("ArchiveElectricMeterHourJob", "All", "任務開始"); EDFunction ed = new EDFunction(); XmlDocument xmlDocument = new XmlDocument(); var sqlArchive = $@"SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'archiveConfig'"; var variableArchive = await backgroundServiceRepository.GetAllAsync(sqlArchive); var electricMeterGuid = variableArchive.Where(x => x.Name == "ElectricMeterGuid").Select(x => x.Value).FirstOrDefault(); #region 找出所有電錶設備 var sWhere = "deleted = 0 AND sub_system_guid = @sub_system_guid"; var electricMeters = await backgroundServiceRepository.GetAllAsync("device", sWhere, new { sub_system_guid = electricMeterGuid }); #endregion 找出所有電錶設備 #region 找出所有電錶系統的點位 var sPointWhere = "deleted = 0 AND sub_system_guid = @sub_system_guid"; var points = await backgroundServiceRepository.GetAllAsync("device_item", sPointWhere, new { sub_system_guid = electricMeterGuid }); #endregion 找出所有電錶系統的點位 #region 組合出所有電錶設備點位 List deviceNumberPoints = new List(); foreach (var electricMeter in electricMeters) { foreach (var point in points) { DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint(); deviceNumberPoint.DeviceNumber = electricMeter.Device_number; deviceNumberPoint.Point = point.points; deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", electricMeter.Device_number, point.points); deviceNumberPoints.Add(deviceNumberPoint); } } #endregion 組合出所有電錶設備點位 #region 取得obix 設定 var obixApiConfig = new ObixApiConfig(); var sqlObix = $@"SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'obixConfig'"; var variableObix = await backgroundServiceRepository.GetAllAsync(sqlObix); obixApiConfig.ApiBase = variableObix.Where(x => x.Name == "ApiBase").Select(x => x.Value).FirstOrDefault(); obixApiConfig.UserName = ed.AESDecrypt(variableObix.Where(x => x.Name == "UserName").Select(x => x.Value).FirstOrDefault()); obixApiConfig.Password = ed.AESDecrypt(variableObix.Where(x => x.Name == "Password").Select(x => x.Value).FirstOrDefault()); String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(obixApiConfig.UserName + ":" + obixApiConfig.Password)); #endregion 取得obix 設定 var now = DateTime.Now; #region 小時歸檔 try { var preHour = now.AddHours(-1); //取得前一小時 var tempHour = string.Empty; if (preHour.Hour < 10) { tempHour = "0" + preHour.Hour.ToString(); } else { tempHour = preHour.Hour.ToString(); } var startTimestamp = string.Format("{0}T{1}:00:00.000+08:00", preHour.ToString("yyyy-MM-dd"), tempHour); var endTimestamp = string.Format("{0}T{1}:59:59.000+08:00", preHour.ToString("yyyy-MM-dd"), tempHour); var historyQueryFilter = $@" "; //Stopwatch stopWatch = new Stopwatch(); //stopWatch.Start(); //抓取每個設備的資料 List> archiveHourRawDatas = new List>(); foreach (var deviceNumberPoint in deviceNumberPoints) { HttpWebRequest archiveHourRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/{deviceNumberPoint.FullDeviceNumberPoint}/~historyRollup/"); //HttpWebRequest archiveHourRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/FIC_Center/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/"); archiveHourRequest.Method = "POST"; archiveHourRequest.Headers.Add("Authorization", "Basic " + encoded); archiveHourRequest.PreAuthenticate = true; byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter); using (Stream reqStream = archiveHourRequest.GetRequestStream()) { reqStream.Write(byteArray, 0, byteArray.Length); } HttpWebResponse archiveHourResponse = (HttpWebResponse)archiveHourRequest.GetResponse(); var archiveHourResponseContent = new StreamReader(archiveHourResponse.GetResponseStream()).ReadToEnd(); xmlDocument.LoadXml(archiveHourResponseContent); string archiveHourJson = JsonConvert.SerializeXmlNode(xmlDocument); JObject archiveHourJsonResult = (JObject)JsonConvert.DeserializeObject(archiveHourJson); if (archiveHourJsonResult.ContainsKey("err")) //抓取錯誤 { //logger.LogError("【ArchiveElectricMeterHourJob】【小時歸檔】【取得資料失敗】"); //logger.LogError("【ArchiveElectricMeterHourJob】【小時歸檔】【取得資料失敗】[錯誤內容]:{0}", archiveHourJsonResult); Dictionary archiveHourRawData = new Dictionary(); archiveHourRawData.Add("@device_number", deviceNumberPoint.DeviceNumber); archiveHourRawData.Add("@point", deviceNumberPoint.Point); archiveHourRawData.Add("@start_timestamp", startTimestamp.Replace("T", " ").Substring(0, 19)); archiveHourRawData.Add("@end_timestamp", endTimestamp.Replace("T", " ").Substring(0, 19)); archiveHourRawData.Add("@is_complete", 0); archiveHourRawData.Add("@repeat_times", 0); archiveHourRawData.Add("@fail_reason", archiveHourJson); archiveHourRawDatas.Add(archiveHourRawData); } if (archiveHourJsonResult.ContainsKey("obj")) //表示可以讀取到內容 { var histories = archiveHourJsonResult["obj"]["list"]; var rawdateCount = Convert.ToInt32(archiveHourJsonResult["obj"]["int"]["@val"].ToString()); if (histories != null && histories.HasValues) { if (rawdateCount > 1) { //多筆資料 foreach (var history in histories) { Dictionary archiveHourRawData = new Dictionary(); archiveHourRawData.Add("@device_number", deviceNumberPoint.DeviceNumber); archiveHourRawData.Add("@point", deviceNumberPoint.Point); //時間 if (history["abstime"] != null && history["abstime"].HasValues) { foreach (var abstime in history["abstime"]) { var name = abstime["@name"].ToString(); switch (name) { case "start": var startTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss"); archiveHourRawData.Add("@start_timestamp", startTimstamp); break; case "end": var endTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss"); archiveHourRawData.Add("@end_timestamp", endTimstamp); break; } } } //區間內資料筆數 if (history["int"] != null && history["int"].HasValues) { var count = Convert.ToInt32(histories["obj"]["int"]["@val"].ToString()); archiveHourRawData.Add("@count_rawdata", count); } //整合數值(最大、最小、平均、總和) if (history["real"] != null && history["real"].HasValues) { foreach (var real in history["real"]) { var name = real["@name"].ToString(); switch (name) { case "min": var min = Convert.ToDecimal(real["@val"].ToString()); archiveHourRawData.Add("@min_rawdata", min); break; case "max": var max = Convert.ToDecimal(real["@val"].ToString()); archiveHourRawData.Add("@max_rawdata", max); break; case "avg": var avg = Convert.ToDecimal(real["@val"].ToString()); archiveHourRawData.Add("@avg_rawdata", avg); break; case "sum": var sum = Convert.ToDecimal(real["@val"].ToString()); archiveHourRawData.Add("@sum_rawdata", sum); break; } } } archiveHourRawData.Add("@is_complete", 1); archiveHourRawDatas.Add(archiveHourRawData); } } else { //單筆資料 Dictionary archiveHourRawData = new Dictionary(); archiveHourRawData.Add("@device_number", deviceNumberPoint.DeviceNumber); archiveHourRawData.Add("@point", deviceNumberPoint.Point); //時間 if (histories["obj"]["abstime"] != null && histories["obj"]["abstime"].HasValues) { foreach (var abstime in histories["obj"]["abstime"]) { var name = abstime["@name"].ToString(); switch (name) { case "start": var startTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss"); archiveHourRawData.Add("@start_timestamp", startTimstamp); break; case "end": var endTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss"); archiveHourRawData.Add("@end_timestamp", endTimstamp); break; } } } //區間內資料筆數 if (histories["obj"]["int"] != null && histories["obj"]["int"].HasValues) { var count = Convert.ToInt32(histories["obj"]["int"]["@val"].ToString()); archiveHourRawData.Add("@count_rawdata", count); } //整合數值(最大、最小、平均、總和) if (histories["obj"]["real"] != null && histories["obj"]["real"].HasValues) { foreach (var real in histories["obj"]["real"]) { var name = real["@name"].ToString(); switch (name) { case "min": var min = Convert.ToDecimal(real["@val"].ToString()); archiveHourRawData.Add("@min_rawdata", min); break; case "max": var max = Convert.ToDecimal(real["@val"].ToString()); archiveHourRawData.Add("@max_rawdata", max); break; case "avg": var avg = Convert.ToDecimal(real["@val"].ToString()); archiveHourRawData.Add("@avg_rawdata", avg); break; case "sum": var sum = Convert.ToDecimal(real["@val"].ToString()); archiveHourRawData.Add("@sum_rawdata", sum); break; } } } archiveHourRawData.Add("@is_complete", 1); archiveHourRawDatas.Add(archiveHourRawData); } } } } //stopWatch.Stop(); //logger.LogInformation("【ArchiveElectricMeterHourJob】【小時歸檔】【效能檢驗】[取得資料花費時間]{0} 毫秒", stopWatch.ElapsedMilliseconds); if (archiveHourRawDatas.Count() > 0) { await backgroundServiceRepository.AddMutiByCustomTable(archiveHourRawDatas, "archive_electric_meter_hour"); } await task_Detail.InsertWorkTime_End("ArchiveElectricMeterHourJob", "All", "任務完成"); } catch (Exception exception) { await task_Detail.WorkFail("ArchiveElectricMeterHourJob", "All", exception.ToString()); logger.LogError("【ArchiveElectricMeterHourJob】【小時歸檔】【任務失敗】"); logger.LogError("【ArchiveElectricMeterHourJob】【小時歸檔】【任務失敗】[Exception]:{0}", exception.ToString()); } #endregion 小時歸檔 } } catch (Exception exception) { await task_Detail.WorkFail("ArchiveElectricMeterHourJob", "All", exception.ToString()); logger.LogError("【ArchiveElectricMeterHourJob】【任務失敗】"); logger.LogError("【ArchiveElectricMeterHourJob】【任務失敗】[Exception]:{0}", exception.ToString()); } } } }