using FrontendWorkerService.Models; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Quartz; using Repository.FrontendRepository.Interface; using Repository.Models; 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 FrontendWorkerService.Quartz.Jobs { /// /// 透過obix API向Niagara更新告警設備狀態值 /// [DisallowConcurrentExecution] class OntimeAlarmDeviceRawDataJob : IJob { private readonly ILogger logger; private readonly IFrontendRepository frontendRepository; public OntimeAlarmDeviceRawDataJob( ILogger logger, IFrontendRepository frontendRepository) { this.logger = logger; this.frontendRepository = frontendRepository; } public async Task Execute(IJobExecutionContext context) { try { logger.LogInformation("【OntimeAlarmDeviceRawDataJob】【任務開始】"); EDFunction ed = new EDFunction(); 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 variable = await frontendRepository.GetAllAsync(sqlObix); obixApiConfig.ApiBase = variable.Where(x => x.Name == "ApiBase").Select(x => x.Value).FirstOrDefault(); obixApiConfig.UserName = ed.AESDecrypt(variable.Where(x => x.Name == "UserName").Select(x => x.Value).FirstOrDefault()); obixApiConfig.Password = ed.AESDecrypt(variable.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)); ObixAlarmConfig obixAlarmConfig = new ObixAlarmConfig(); obixAlarmConfig.Alarm_watch_id = variable.Where(x => x.Name == "alarm_watch_id").Select(x => x.Value).FirstOrDefault(); HttpWebRequest request = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/watchService/watch{obixAlarmConfig.Alarm_watch_id}/pollChanges/"); request.Method = "POST"; request.Headers.Add("Authorization", "Basic " + encoded); request.PreAuthenticate = true; //Stopwatch stopWatch = new Stopwatch(); //stopWatch.Start(); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); var responseContent = new StreamReader(response.GetResponseStream()).ReadToEnd(); //stopWatch.Stop(); //logger.LogInformation("【OntimeAlarmDeviceRawDataJob】【效能檢驗】[取得資料花費時間]{0} 毫秒", stopWatch.ElapsedMilliseconds); //stopWatch.Reset(); //stopWatch.Start(); XmlDocument xmlDocument = new XmlDocument(); xmlDocument.LoadXml(responseContent); string json = JsonConvert.SerializeXmlNode(xmlDocument); JObject jsonResult = (JObject)JsonConvert.DeserializeObject(json); if (jsonResult.ContainsKey("err")) //抓取錯誤 { logger.LogError("【OntimeAlarmDeviceRawDataJob】【API回傳錯誤資訊】"); logger.LogError("【OntimeAlarmDeviceRawDataJob】【API回傳錯誤資訊】[錯誤內容]:{0}", json); #region 刪除舊有watch service logger.LogInformation("【OntimeAlarmDeviceRawDataJob】【開始刪除該watch service】[編號:{0}]", obixAlarmConfig.Alarm_watch_id); HttpWebRequest deleteWatchServiceRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/watchService/watch{obixAlarmConfig.Alarm_watch_id}/delete/"); deleteWatchServiceRequest.Method = "POST"; deleteWatchServiceRequest.Headers.Add("Authorization", "Basic " + encoded); deleteWatchServiceRequest.PreAuthenticate = true; HttpWebResponse deleteWatchServiceResponse = (HttpWebResponse)deleteWatchServiceRequest.GetResponse(); var deleteWatchServiceResponseContent = new StreamReader(deleteWatchServiceResponse.GetResponseStream()).ReadToEnd(); xmlDocument.LoadXml(deleteWatchServiceResponseContent); string deleteWatchServiceJson = JsonConvert.SerializeXmlNode(xmlDocument); JObject deleteWatchServiceJsonResult = (JObject)JsonConvert.DeserializeObject(deleteWatchServiceJson); if (deleteWatchServiceJsonResult.ContainsKey("err")) //抓取錯誤 { logger.LogError("【OnTimeDeviceSubscriptionJob】【刪除舊有watch service失敗】[編號:{0}]"); logger.LogError("【OnTimeDeviceSubscriptionJob】【刪除舊有watch service失敗】[錯誤內容]:{0}", deleteWatchServiceJson); } else if (deleteWatchServiceJsonResult.ContainsKey("obj")) { var deleteResult = deleteWatchServiceJsonResult["obj"]["@null"].ToString(); if (deleteResult == "true") { logger.LogInformation("【OntimeAlarmDeviceRawDataJob】【刪除舊有watch service成功】[編號:{0}]", obixAlarmConfig.Alarm_watch_id); } else { logger.LogError("【OntimeAlarmDeviceRawDataJob】【刪除舊有watch service失敗】[編號:{0}]", obixAlarmConfig.Alarm_watch_id); logger.LogError("【OntimeAlarmDeviceRawDataJob】【刪除舊有watch service失敗】[錯誤內容]:{0}", deleteWatchServiceJson); } } else //未知錯誤 { logger.LogError("【OntimeAlarmDeviceRawDataJob】【刪除舊有watch service未知錯誤】[編號:{0}]", obixAlarmConfig.Alarm_watch_id); logger.LogError("【OntimeAlarmDeviceRawDataJob】【刪除舊有watch service未知錯誤】[錯誤內容]:{0}", deleteWatchServiceJson); } #endregion #region 重新建立watch service logger.LogInformation("【OntimeAlarmDeviceRawDataJob】【開始重新建立watch service】"); string watch_id = string.Empty; //紀錄watch id的編號 //重新建立watch service HttpWebRequest makeWatchServiceRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/watchService/make/"); makeWatchServiceRequest.Method = "POST"; makeWatchServiceRequest.Headers.Add("Authorization", "Basic " + encoded); makeWatchServiceRequest.PreAuthenticate = true; HttpWebResponse makeWatchServiceResponse = (HttpWebResponse)makeWatchServiceRequest.GetResponse(); var makeWatchServiceResponseContent = new StreamReader(makeWatchServiceResponse.GetResponseStream()).ReadToEnd(); xmlDocument.LoadXml(makeWatchServiceResponseContent); string makeWatchServiceJson = JsonConvert.SerializeXmlNode(xmlDocument); JObject makeWatchServiceJsonResult = (JObject)JsonConvert.DeserializeObject(makeWatchServiceJson); if (makeWatchServiceJsonResult.ContainsKey("err")) //抓取錯誤 { logger.LogError("【OnTimeDeviceSubscriptionJob】【重新建立watch service失敗】"); logger.LogError("【OnTimeDeviceSubscriptionJob】【重新建立watch service失敗】[錯誤內容]:{0}", makeWatchServiceJson); return; } if (makeWatchServiceJsonResult.ContainsKey("obj")) //表示可以讀取到內容 { var makeSplit = makeWatchServiceJsonResult["obj"]["@href"].ToString().Split("/"); watch_id = makeSplit[makeSplit.Length - 2].Replace("watch", ""); } if (!string.IsNullOrEmpty(watch_id)) { logger.LogInformation("【OntimeAlarmDeviceRawDataJob】【重新建立watch service的編號】[編號:{0}]", watch_id); //儲存至variable Dictionary updateWatchId = new Dictionary() { { "@system_value", watch_id} }; await frontendRepository.UpdateOneByCustomTable(updateWatchId, "variable", "system_type = 'obixConfig' AND system_key = 'alarm_watch_id'"); //修改watch service 存活時間 HttpWebRequest changeWatchServiceRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/watchService/watch{watch_id}/lease/"); changeWatchServiceRequest.Method = "PUT"; changeWatchServiceRequest.Headers.Add("Authorization", "Basic " + encoded); changeWatchServiceRequest.PreAuthenticate = true; var realTime = $@""; byte[] realTimeByteArray = Encoding.UTF8.GetBytes(realTime); using (Stream reqStream = changeWatchServiceRequest.GetRequestStream()) { reqStream.Write(realTimeByteArray, 0, realTimeByteArray.Length); } HttpWebResponse changeWatchServiceResponse = (HttpWebResponse)changeWatchServiceRequest.GetResponse(); var changeWatchServiceResponseContent = new StreamReader(changeWatchServiceResponse.GetResponseStream()).ReadToEnd(); xmlDocument.LoadXml(changeWatchServiceResponseContent); string changeWatchServiceJson = JsonConvert.SerializeXmlNode(xmlDocument); JObject changeWatchServiceJsonResult = (JObject)JsonConvert.DeserializeObject(changeWatchServiceJson); if (changeWatchServiceJsonResult.ContainsKey("err")) //抓取錯誤 { logger.LogError("【OnTimeDeviceSubscriptionJob】【修改watch service存活時間失敗】"); logger.LogError("【OnTimeDeviceSubscriptionJob】【修改watch service存活時間失敗】[錯誤內容]:{0}", changeWatchServiceJsonResult); return; } } #endregion #region 訂閱alarm feed HttpWebRequest addWatchServiceRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/watchService/watch{watch_id}/add/"); addWatchServiceRequest.Method = "POST"; addWatchServiceRequest.Headers.Add("Authorization", "Basic " + encoded); addWatchServiceRequest.PreAuthenticate = true; var subscripFullString = $@" "; byte[] byteArray = Encoding.UTF8.GetBytes(subscripFullString); using (Stream reqStream = addWatchServiceRequest.GetRequestStream()) { reqStream.Write(byteArray, 0, byteArray.Length); } HttpWebResponse addWatchServiceResponse = (HttpWebResponse)addWatchServiceRequest.GetResponse(); var addWatchServiceResponseContent = new StreamReader(addWatchServiceResponse.GetResponseStream()).ReadToEnd(); xmlDocument.LoadXml(addWatchServiceResponseContent); string addWatchServiceJson = JsonConvert.SerializeXmlNode(xmlDocument); JObject addWatchServiceJsonResult = (JObject)JsonConvert.DeserializeObject(addWatchServiceJson); if (addWatchServiceJsonResult.ContainsKey("err")) //抓取錯誤 { logger.LogError("【OntimeAlarmDeviceSubscriptionJob】【告警設備訂閱失敗】"); logger.LogError("【OntimeAlarmDeviceSubscriptionJob】【告警設備訂閱失敗】[錯誤內容]:{0}", addWatchServiceJsonResult); return; } #endregion } else { if (jsonResult.ContainsKey("obj")) //表示可以讀取到內容 { //logger.LogInformation("【OntimeAlarmDeviceRawDataJob】【取得資料內容】{0}", System.Text.Json.JsonSerializer.Serialize(json)); List> ontimeAlarmRawDatas = new List>(); List tempDeviceNumbers = new List(); //用來找出設備的區域、系統大小類GUID List alarmRawDataPreprocesses = new List(); var alarmList = jsonResult["obj"]["list"]["feed"]; if (alarmList["obj"] != null && alarmList["obj"].HasValues) { //讀取資料 foreach (var obj in alarmList["obj"]) { var sourceState = string.Empty; var sourceName = string.Empty; //找出 foreach (var str in obj["str"]) { var tempName = str["@name"].ToString(); if (tempName == "toState") { sourceState = str["@val"].ToString(); } if (tempName == "sourceName") { sourceName = str["@val"].ToString(); } } if (!string.IsNullOrEmpty(sourceName)) { var sourceNameSplit = sourceName.Split("_"); var device_number = string.Join("_", sourceNameSplit, 0, sourceNameSplit.Length - 1); //找出設備編號 var name = sourceNameSplit[sourceNameSplit.Length - 1];//找出點位 tempDeviceNumbers.Add(device_number); OntimeAlarmRawDataPreprocess alarmRawDataPreprocess = new OntimeAlarmRawDataPreprocess() { DeviceNumber = device_number, Name = name, SourceStatus = sourceState }; alarmRawDataPreprocesses.Add(alarmRawDataPreprocess); } } } if (alarmRawDataPreprocesses.Count() > 0) { //找出設備的區域、系統大小類GUID var sql = $@"SELECT * FROM device d WHERE d.deleted = 0 AND d.device_number IN @DeviceNumbers"; var deviceInfos = await frontendRepository.GetAllAsync(sql, new { DeviceNumbers = tempDeviceNumbers }); foreach (var alarmRawDataPreprocess in alarmRawDataPreprocesses) { var selectedDeviceInfo = deviceInfos.Where(x => x.device_number == alarmRawDataPreprocess.DeviceNumber).FirstOrDefault(); if (selectedDeviceInfo != null) { Dictionary ontimeAlarmRawData = new Dictionary() { { "@building_guid", selectedDeviceInfo.building_guid }, { "@main_system_guid", selectedDeviceInfo.main_system_guid }, { "@sub_system_guid", selectedDeviceInfo.sub_system_guid }, { "@floor_guid", selectedDeviceInfo.floor_guid }, { "@device_number", alarmRawDataPreprocess.DeviceNumber}, { "@name", alarmRawDataPreprocess.Name}, { "@source_state", alarmRawDataPreprocess.SourceStatus}, }; ontimeAlarmRawDatas.Add(ontimeAlarmRawData); } } } //stopWatch.Stop(); //logger.LogInformation("【OntimeAlarmDeviceRawDataJob】【效能檢驗】[解析資料花費時間]{0} 毫秒", stopWatch.ElapsedMilliseconds); if (ontimeAlarmRawDatas.Count() > 0) { try { //stopWatch.Reset(); //stopWatch.Start(); var insert_update_sql = $@"INSERT INTO ontime_alarm_device_rawdata (building_guid, main_system_guid, sub_system_guid, device_number, name, source_state) VALUES(@building_guid, @main_system_guid, @sub_system_guid, @device_number, @name, @source_state) ON DUPLICATE KEY UPDATE source_state=@source_state"; await frontendRepository.ExecuteSql(insert_update_sql, ontimeAlarmRawDatas); //stopWatch.Stop(); //logger.LogInformation("【OntimeAlarmDeviceRawDataJob】【效能檢驗】[資料存入資料庫花費時間]{0} 毫秒", stopWatch.ElapsedMilliseconds); //logger.LogInformation("【OntimeAlarmDeviceRawDataJob】【存入資料內容】:{0}", System.Text.Json.JsonSerializer.Serialize(ontimeAlarmRawDatas)); } catch (Exception exception) { logger.LogError("【OntimeAlarmDeviceSubscriptionJob】【新增設備點位原始資料失敗】"); logger.LogError("【OntimeAlarmDeviceSubscriptionJob】【新增設備點位原始資料失敗】[Exception]:{0}", exception.ToString()); } } } } logger.LogInformation("【OntimeAlarmDeviceRawDataJob】【任務完成】"); } catch (Exception exception) { logger.LogError("【OntimeAlarmDeviceRawDataJob】【任務失敗】"); logger.LogError("【OntimeAlarmDeviceRawDataJob】【任務失敗】[Exception]:{0}", exception.ToString()); } } } }