From b60530974f881428a756170af81bf088c70800d4 Mon Sep 17 00:00:00 2001 From: "jay.chang" Date: Tue, 26 Nov 2024 17:27:46 +0800 Subject: [PATCH] =?UTF-8?q?[BGService]=E5=B0=87=E9=83=A8=E5=88=86obix?= =?UTF-8?q?=E5=AE=9A=E6=99=82=E4=BB=BB=E5=8B=99=E6=94=B9=E6=88=90=E6=89=B9?= =?UTF-8?q?=E6=AC=A1=E6=92=88=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Quartz/Jobs/LightScheduleJob .cs | 382 ++++++++++++++---- .../Quartz/Jobs/ParkingJob.cs | 249 ++++++------ .../Quartz/Jobs/WeatherAPIJob.cs | 188 ++++++++- 3 files changed, 595 insertions(+), 224 deletions(-) diff --git a/BackendWorkerService/Quartz/Jobs/LightScheduleJob .cs b/BackendWorkerService/Quartz/Jobs/LightScheduleJob .cs index 9c3ffa0..c2ef1a5 100644 --- a/BackendWorkerService/Quartz/Jobs/LightScheduleJob .cs +++ b/BackendWorkerService/Quartz/Jobs/LightScheduleJob .cs @@ -38,14 +38,13 @@ namespace BackendWorkerService.Quartz.Jobs private readonly IBackendRepository backendRepository; private readonly ILogger loggers; public LightScheduleJob(ILogger logger, - IBackgroundServiceRepository backgroundServiceRepository, IBackendRepository backendRepository, ILogger loggers) + IBackgroundServiceRepository backgroundServiceRepository, IBackendRepository backendRepository, ILogger loggers) { this.logger = logger; this.backgroundServiceRepository = backgroundServiceRepository; this.backendRepository = backendRepository; this.loggers = loggers; } - public async Task Execute(IJobExecutionContext context) { Task_Detail task_Detail = new Task_Detail(loggers, backendRepository); @@ -58,33 +57,13 @@ namespace BackendWorkerService.Quartz.Jobs await task_Detail.InsertWorkTime("LightScheduleJob", "light_schedule"); var TimeNow = DateTime.Now.ToString("dddd HH:mm"); - var schedule = await backendRepository.GetAllAsync("light_schedule","deleted = 0 and status = 1"); + var schedule = await backendRepository.GetAllAsync("light_schedule", "deleted = 0 and status = 1"); + string date = DateTime.Now.ToString("yyyy-MM-dd"); foreach (var oneSchedule in schedule) { - // 檢查執行log - string light_schedule_guid = oneSchedule.light_schedule_guid; - string sWhere = @$"light_schedule_guid = '{light_schedule_guid}' and date = '{date}'"; - var schedule_log = await backendRepository.GetOneAsync("light_schedule_log", sWhere); - string start_time = null; - string end_time = null; - if (schedule_log != null) - { - start_time = schedule_log.start_time; - end_time = schedule_log.end_time; - } - if (schedule_log == null) - { - Dictionary log = new Dictionary() - { - { "@light_schedule_guid", light_schedule_guid}, - { "@date", date}, - }; - await backendRepository.AddOneByCustomTable(log, "light_schedule_log"); - } - // 如果log有紀錄 - + // 先檢查今日否需執行 var weeklistN = oneSchedule.week.Split(','); List weeklist = new List(); foreach (var weekN in weeklistN) @@ -102,35 +81,53 @@ namespace BackendWorkerService.Quartz.Jobs }; weeklist.Add(week); } + var Time = TimeNow.Split(" "); - string check = string.Empty; - // 檢查起始執行 - if (start_time == null && DateTime.Parse(Time[1]) >= DateTime.Parse(oneSchedule.start_time)) - { - check = ""; - UpdatedNiagara(oneSchedule, check); - Dictionary log = new Dictionary() - { - { "@start_time", Time[1]}, - }; - await backendRepository.UpdateOneByCustomTable(log, "light_schedule_log", $"light_schedule_guid = '{light_schedule_guid}' and date = '{date}'"); - logger.LogInformation($"【LightScheduleJob】【燈控排程開啟成功】排程名稱 :{oneSchedule.full_name}"); + if (!weeklist.Contains(Time[0])) { continue; } + + // 檢查執行log + string light_schedule_guid = oneSchedule.light_schedule_guid; + string sWhere = @$"light_schedule_guid = '{light_schedule_guid}' and date = '{date}'"; + var schedule_log = await backendRepository.GetOneAsync("light_schedule_log", sWhere); + string start_time = null; + string end_time = null; + if (schedule_log != null) + { + start_time = schedule_log.start_time; + end_time = schedule_log.end_time; } + + if (schedule_log == null) + { + Dictionary log = new Dictionary() + { + { "@light_schedule_guid", light_schedule_guid }, + { "@date", date }, + }; + await backendRepository.AddOneByCustomTable(log, "light_schedule_log"); + } + + + string check = string.Empty; + + // 檢查起始執行 + if (start_time == null && end_time == null && DateTime.Parse(Time[1]) >= DateTime.Parse(oneSchedule.start_time)) + { + check = "true"; // 開啟 + } + // 檢查結束執行 if (end_time == null && DateTime.Parse(Time[1]) >= DateTime.Parse(oneSchedule.end_time)) { - check = ""; - UpdatedNiagara(oneSchedule, check); - Dictionary log = new Dictionary() - { - { "@end_time", Time[1]}, - }; - await backendRepository.UpdateOneByCustomTable(log, "light_schedule_log", $"light_schedule_guid = '{light_schedule_guid}' and date = '{date}'"); - logger.LogInformation($"【LightScheduleJob】【燈控排程關閉成功】排程名稱 :{oneSchedule.full_name}"); + check = "false"; // 關閉 + } + + if (!string.IsNullOrEmpty(check)) + { + bool requestSuccess = await UpdatedNiagara(oneSchedule, check); } } - await task_Detail.InsertWorkTime_End("LightScheduleJob", "light_schedule"); } catch (Exception ex) @@ -146,52 +143,279 @@ namespace BackendWorkerService.Quartz.Jobs logger.LogError("【LightScheduleJob】【任務失敗】[Exception]:{0}", exception.ToString()); } } - public async void UpdatedNiagara(Schedule oneSchedule, string check) + + public async Task UpdatedNiagara(Schedule oneSchedule, string check) { try { - var deviceNumList = await backendRepository.GetAllAsync(@$"select d.device_number from schedule_device sd join device d on sd.device_guid = d.device_guid - where light_schedule_guid = '{oneSchedule.light_schedule_guid}' and is_link = 1"); + // 取得排程所對應的設備號碼列表 + var deviceNumList = await backendRepository.GetAllAsync(@$"SELECT d.device_number + FROM schedule_device sd + JOIN device d ON sd.device_guid = d.device_guid + WHERE light_schedule_guid = '{oneSchedule.light_schedule_guid}' AND is_link = 1"); + + // 取得obix配置 + var variableObix = await backendRepository.GetAllAsync(@$"SELECT system_value as Value, system_key as Name + FROM variable + WHERE deleted = 0 AND system_type = 'obixConfig'"); + + // 取得obix相關配置參數 + string url = variableObix.FirstOrDefault(x => x.Name == "ApiBase")?.Value; + string account = variableObix.FirstOrDefault(x => x.Name == "UserName")?.Value; + string pass = variableObix.FirstOrDefault(x => x.Name == "Password")?.Value; + + // 檢查是否有配置缺失 + if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(account) || string.IsNullOrEmpty(pass)) + { + logger.LogWarning("【LightScheduleJob】【obix配置缺失】請檢查obix配置"); + return false; + } + + // 準備HTTP請求的基本資訊 + string authInfo = Convert.ToBase64String(Encoding.Default.GetBytes($"{account}:{pass}")); + + // 構建每個設備的請求 + List batchRequests = new List(); + TagChangeFunction tagChange = new TagChangeFunction(); - var variableObix = await backendRepository.GetAllAsync("SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'obixConfig'"); - string url = variableObix.Where(x => x.Name == "ApiBase").Select(x => x.Value).FirstOrDefault(); - string account = variableObix.Where(x => x.Name == "UserName").Select(x => x.Value).FirstOrDefault(); - string pass = variableObix.Where(x => x.Name == "Password").Select(x => x.Value).FirstOrDefault(); foreach (var deviceNum in deviceNumList) { - TagChangeFunction tagChange = new TagChangeFunction(); + // 處理設備號碼,分解到URL中 var d = tagChange.AddStringIfStartsWithDigit(deviceNum, "$3"); - var html = $"{url}obix/config/Arena/" + $"{d[0]}/{d[1]}/{d[2]}/{d[3]}/{deviceNum}/SSC/set"; - string authInfo = account + ":" + pass; - authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo)); - HttpWebRequest request = (HttpWebRequest)WebRequest.Create(html); - request.Method = "POST"; - request.Accept = "application/json; charset=utf-8"; - request.Headers["Authorization"] = "Basic " + authInfo; - byte[] byteArray = Encoding.UTF8.GetBytes(check); - using (Stream reqStream = request.GetRequestStream()) - { - reqStream.Write(byteArray, 0, byteArray.Length); - } - var response = (HttpWebResponse)request.GetResponse(); - string strResponse = ""; + var uri = $"{url}obix/config/Arena/{d[0]}/{d[1]}/{d[2]}/{d[3]}/{deviceNum}/SSC/set"; - using (var sr = new StreamReader(response.GetResponseStream())) - { - strResponse = sr.ReadToEnd(); - } - // 只取err會取到override - if (strResponse.Contains(""; + + // 建立批次請求 + batchRequests.Add($"" + realData + ""); } + + // 構建整體批次請求 + var batchRequestData = $@" + {string.Join("", batchRequests)} + "; + + // 發送批次請求 + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url + "obix/batch"); + request.Method = "POST"; + request.Accept = "application/json; charset=utf-8"; + request.Headers["Authorization"] = "Basic " + authInfo; + + // 將所有設備的請求內容合併成一個批次請求 + byte[] byteArray = Encoding.UTF8.GetBytes(batchRequestData); + using (Stream reqStream = request.GetRequestStream()) + { + reqStream.Write(byteArray, 0, byteArray.Length); + } + + // 發送請求並處理回應 + var response = (HttpWebResponse)request.GetResponse(); + string responseContent = string.Empty; + + using (var sr = new StreamReader(response.GetResponseStream())) + { + responseContent = sr.ReadToEnd(); + } + + + // 檢查回應中是否有錯誤 + if (responseContent.Contains(" log = new Dictionary(); + + string time = DateTime.Now.ToString("HH:mm"); + if (check == "true") + { + log.Add("@start_time", time); + } + else + { + log.Add("@end_time", time); + } + + + await backendRepository.UpdateOneByCustomTable(log, "light_schedule_log", $"light_schedule_guid = '{oneSchedule.light_schedule_guid}' and date = '{DateTime.Now:yyyy-MM-dd}'"); + + logger.LogInformation($"【LightScheduleJob】【Niagara燈控設置成功】排程名稱 :{oneSchedule.full_name}"); + return true; } catch (Exception ex) { - logger.LogError("【LightScheduleJob】" + "UpdatedNiagaraFail:" + ex.ToString()); - throw ex; + logger.LogError("【LightScheduleJob】批次請求發送失敗:" + ex.ToString()); + return false; } } + + + + + + + + //public async Task Execute(IJobExecutionContext context) + //{ + // Task_Detail task_Detail = new Task_Detail(loggers, backendRepository); + // try + // { + // if (await task_Detail.GetNeedWorkTask("LightScheduleJob", "light_schedule")) + // { + // try + // { + // await task_Detail.InsertWorkTime("LightScheduleJob", "light_schedule"); + + // var TimeNow = DateTime.Now.ToString("dddd HH:mm"); + // var schedule = await backendRepository.GetAllAsync("light_schedule","deleted = 0 and status = 1"); + // string date = DateTime.Now.ToString("yyyy-MM-dd"); + + // foreach (var oneSchedule in schedule) + // { + // // 檢查執行log + // string light_schedule_guid = oneSchedule.light_schedule_guid; + // string sWhere = @$"light_schedule_guid = '{light_schedule_guid}' and date = '{date}'"; + // var schedule_log = await backendRepository.GetOneAsync("light_schedule_log", sWhere); + // string start_time = null; + // string end_time = null; + // if (schedule_log != null) + // { + // start_time = schedule_log.start_time; + // end_time = schedule_log.end_time; + // } + // if (schedule_log == null) + // { + // Dictionary log = new Dictionary() + // { + // { "@light_schedule_guid", light_schedule_guid}, + // { "@date", date}, + // }; + // await backendRepository.AddOneByCustomTable(log, "light_schedule_log"); + // } + // // 如果log有紀錄 + + // var weeklistN = oneSchedule.week.Split(','); + // List weeklist = new List(); + // foreach (var weekN in weeklistN) + // { + // var week = weekN switch + // { + // "0" => "星期日", + // "1" => "星期一", + // "2" => "星期二", + // "3" => "星期三", + // "4" => "星期四", + // "5" => "星期五", + // "6" => "星期六", + // _ => "" + // }; + // weeklist.Add(week); + // } + // var Time = TimeNow.Split(" "); + // string check = string.Empty; + // // 檢查起始執行 + // if (start_time == null && DateTime.Parse(Time[1]) >= DateTime.Parse(oneSchedule.start_time)) + // { + // check = ""; + // UpdatedNiagara(oneSchedule, check); + // Dictionary log = new Dictionary() + // { + // { "@start_time", Time[1]}, + // }; + // await backendRepository.UpdateOneByCustomTable(log, "light_schedule_log", $"light_schedule_guid = '{light_schedule_guid}' and date = '{date}'"); + // logger.LogInformation($"【LightScheduleJob】【燈控排程開啟成功】排程名稱 :{oneSchedule.full_name}"); + // } + // // 檢查結束執行 + // if (end_time == null && DateTime.Parse(Time[1]) >= DateTime.Parse(oneSchedule.end_time)) + // { + // check = ""; + // UpdatedNiagara(oneSchedule, check); + // Dictionary log = new Dictionary() + // { + // { "@end_time", Time[1]}, + // }; + // await backendRepository.UpdateOneByCustomTable(log, "light_schedule_log", $"light_schedule_guid = '{light_schedule_guid}' and date = '{date}'"); + // logger.LogInformation($"【LightScheduleJob】【燈控排程關閉成功】排程名稱 :{oneSchedule.full_name}"); + // } + // } + + + // await task_Detail.InsertWorkTime_End("LightScheduleJob", "light_schedule"); + // } + // catch (Exception ex) + // { + // logger.LogInformation($"LightScheduleJob fail"); + // await task_Detail.WorkFail("LightScheduleJob", "light_schedule", ex.Message.ToString()); + // } + // } + // } + // catch (Exception exception) + // { + // logger.LogError("【LightScheduleJob】【任務失敗】"); + // logger.LogError("【LightScheduleJob】【任務失敗】[Exception]:{0}", exception.ToString()); + // } + //} + //public async void UpdatedNiagara(Schedule oneSchedule, string check) + //{ + // try + // { + // var deviceNumList = await backendRepository.GetAllAsync(@$"select d.device_number from schedule_device sd join device d on sd.device_guid = d.device_guid + // where light_schedule_guid = '{oneSchedule.light_schedule_guid}' and is_link = 1"); + + // var variableObix = await backendRepository.GetAllAsync("SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'obixConfig'"); + // string url = variableObix.Where(x => x.Name == "ApiBase").Select(x => x.Value).FirstOrDefault(); + // string account = variableObix.Where(x => x.Name == "UserName").Select(x => x.Value).FirstOrDefault(); + // string pass = variableObix.Where(x => x.Name == "Password").Select(x => x.Value).FirstOrDefault(); + // foreach (var deviceNum in deviceNumList) + // { + // TagChangeFunction tagChange = new TagChangeFunction(); + // var d = tagChange.AddStringIfStartsWithDigit(deviceNum, "$3"); + // var html = $"{url}obix/config/Arena/" + $"{d[0]}/{d[1]}/{d[2]}/{d[3]}/{deviceNum}/SSC/set"; + // string authInfo = account + ":" + pass; + // authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo)); + // HttpWebRequest request = (HttpWebRequest)WebRequest.Create(html); + // request.Method = "POST"; + // request.Accept = "application/json; charset=utf-8"; + // request.Headers["Authorization"] = "Basic " + authInfo; + // byte[] byteArray = Encoding.UTF8.GetBytes(check); + // using (Stream reqStream = request.GetRequestStream()) + // { + // reqStream.Write(byteArray, 0, byteArray.Length); + // } + // var response = (HttpWebResponse)request.GetResponse(); + // string strResponse = ""; + + // using (var sr = new StreamReader(response.GetResponseStream())) + // { + // strResponse = sr.ReadToEnd(); + // } + // // 只取err會取到override + // if (strResponse.Contains(" batchRequests = new List(); // 用來存儲批次請求的列表 + foreach (var area in spaceResponseResult.Payload.Areas) { - //找出對定的設備代碼 - var selectedMapping = parkingSapceMapping.Where(x => x.System_key == area.Name).FirstOrDefault(); + // 找出對應的設備代碼 + var selectedMapping = parkingSapceMapping.FirstOrDefault(x => x.System_key == area.Name); if (selectedMapping != null) { - item = area.Name; + var name = area.Name; // 保存設備名稱 var tagName = selectedMapping.system_value; var apiFormat = @"{0}obix/config/Arena/{1}/{2}/{3}/{4}/{5}/CV/set"; var tagNameSplit = tagName.Split("_"); - var parames = new List(); - parames.Add(parkingConfig.ApiBase); - for (var i = 0; i < tagNameSplit.Length; i++) - { - if (i != tagNameSplit.Length - 1) - { - parames.Add(tagNameSplit[i]); // tag 前 4段 - } - else - { - parames.Add(tagName); // 第五段 完整 tag - } - } - //logger.LogError(@$"【ParkingJob】【停車場剩餘車位】{apiFormat}"); - HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(apiFormat, parames.ToArray())); - request.Method = "POST"; - request.Headers.Add("Authorization", "Basic " + encoded); - request.PreAuthenticate = true; - request.Timeout = System.Threading.Timeout.Infinite; + var parames = new List { parkingConfig.ApiBase }; + parames.AddRange(tagNameSplit.Take(tagNameSplit.Length - 1)); // tag 前 4段 + parames.Add(tagName); // 最後一段 完整 tag + string requestUri = string.Format(apiFormat, parames.ToArray()); + + // 構建要發送的實體資料 var real = $@""; - byte[] realByteArray = Encoding.UTF8.GetBytes(real); - using (Stream reqStream = request.GetRequestStream()) - { - reqStream.Write(realByteArray, 0, realByteArray.Length); - } - HttpWebResponse response = (HttpWebResponse)request.GetResponse(); - var responseContent = new StreamReader(response.GetResponseStream()).ReadToEnd(); + batchRequests.Add($"" + + $"" + + $""); - XmlDocument xmlDocument = new XmlDocument(); - xmlDocument.LoadXml(responseContent); - string json = JsonConvert.SerializeXmlNode(xmlDocument); - JObject jsonResult = (JObject)JsonConvert.DeserializeObject(json); - - if (jsonResult.ContainsKey("err")) //抓取錯誤 - { - logger.LogError("【ParkingJob】【停車場剩餘車位資訊】"); - logger.LogError("【ParkingJob】【停車場剩餘車位資訊】[錯誤內容]:{0}", json); - } - else - { - if (jsonResult.ContainsKey("real")) //表示可以讀取到內容 - { - List> ontimeRawDatas = new List>(); - - var realList = jsonResult["real"]; - var display = realList["@display"]; - if (display != null) - { - var tempStrSplit = display.ToString().Split(" "); - if (tempStrSplit[0] != area.Remain.ToString()) - { - logger.LogError("【ParkingJob】【停車場剩餘車位資訊】[修改失敗]:{0}", display.ToString()); - } - else - { - logger.LogInformation("【ParkingJob】【停車場剩餘車位資訊】[修改成功]:{0}", display.ToString()); - logger.LogInformation("【ParkingJob】【停車場剩餘車位資訊】[停車場資訊]:{0}", item); - } - } - } - } + // 進行日誌記錄 + logger.LogInformation("【ParkingJob】【停車場剩餘車位】準備更新設備:{0},剩餘車位數:{1}", name, area.Remain); } else { @@ -175,11 +129,59 @@ namespace BackendWorkerService.Quartz.Jobs } } + if (batchRequests.Any()) + { + // 建立批次請求 XML + var batchRequestXml = $@" + {string.Join("", batchRequests)} + "; + + // 發送批次請求 + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(parkingConfig.ApiBase + "obix/batch"); + request.Method = "POST"; + request.Headers.Add("Authorization", "Basic " + encoded); + request.PreAuthenticate = true; + request.Timeout = System.Threading.Timeout.Infinite; + + byte[] requestData = Encoding.UTF8.GetBytes(batchRequestXml); + using (Stream reqStream = request.GetRequestStream()) + { + reqStream.Write(requestData, 0, requestData.Length); + } + + HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + var responseContent = new StreamReader(response.GetResponseStream()).ReadToEnd(); + // 檢查回應中是否有錯誤 + if (responseContent.Contains(" batchRequests = new List(); // 用來存儲批次請求的列表 + foreach (var equipment in equipmentResponseResult.Payload) { - //找出對定的設備代碼 - var selectedMapping = parkingEquipmentMapping.Where(x => x.System_key == equipment.Id).FirstOrDefault(); + // 找出對應的設備代碼 + var selectedMapping = parkingEquipmentMapping.FirstOrDefault(x => x.System_key == equipment.Id); if (selectedMapping != null) { - item = equipment.Id; + var name = equipment.Id; // 保存設備ID var tagName = selectedMapping.system_value; var apiFormat = @"{0}obix/config/Arena/{1}/{2}/{3}/{4}/{5}/ST/set"; var tagNameSplit = tagName.Split("_"); - var parames = new List(); - parames.Add(parkingConfig.ApiBase); - for (var i = 0; i < tagNameSplit.Length; i++) - { - if (i != tagNameSplit.Length - 1) - { - parames.Add(tagNameSplit[i]); - } - else - { - parames.Add(tagName); - } - } + var parames = new List { parkingConfig.ApiBase }; + parames.AddRange(tagNameSplit.Take(tagNameSplit.Length - 1)); // tag 前 4段 + parames.Add(tagName); // 最後一段 完整 tag - HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(apiFormat, parames.ToArray())); - request.Method = "POST"; - request.Headers.Add("Authorization", "Basic " + encoded); - request.PreAuthenticate = true; + string requestUri = string.Format(apiFormat, parames.ToArray()); + // 構建要發送的實體資料 var real = $@""; - byte[] realByteArray = Encoding.UTF8.GetBytes(real); - using (Stream reqStream = request.GetRequestStream()) - { - reqStream.Write(realByteArray, 0, realByteArray.Length); - } + batchRequests.Add($"" + + $"" + + $""); - HttpWebResponse response = (HttpWebResponse)request.GetResponse(); - var responseContent = new StreamReader(response.GetResponseStream()).ReadToEnd(); - - XmlDocument xmlDocument = new XmlDocument(); - xmlDocument.LoadXml(responseContent); - string json = JsonConvert.SerializeXmlNode(xmlDocument); - JObject jsonResult = (JObject)JsonConvert.DeserializeObject(json); - - if (jsonResult.ContainsKey("err")) //抓取錯誤 - { - logger.LogError("【ParkingJob】【設備資訊】"); - logger.LogError("【ParkingJob】【設備資訊】[錯誤內容]:{0}", json); - } - else - { - if (jsonResult.ContainsKey("bool")) //表示可以讀取到內容 - { - List> ontimeRawDatas = new List>(); - - var realList = jsonResult["bool"]; - var val = realList["@val"]; - if (val != null) - { - var tempStrSplit = val.ToString(); - if (tempStrSplit != equipment.Alive.ToString().ToLower()) - { - logger.LogError("【ParkingJob】【設備資訊】[修改失敗]:{0}", val.ToString()); - } - else - { - logger.LogInformation("【ParkingJob】【設備資訊】[修改成功]:{0}", val.ToString()); - logger.LogInformation("【ParkingJob】【設備資訊】[設備資訊]:{0}", item); - } - } - } - } + // 進行日誌記錄 + logger.LogInformation("【ParkingJob】【設備資訊】準備更新設備:{0},設備狀態:{1}", name, equipment.Alive); } else { logger.LogWarning("【ParkingJob】【設備資訊】[查無該名稱對應表]:{0}", equipment.Id); } } + + if (batchRequests.Any()) + { + // 建立批次請求 XML + var batchRequestXml = $@" + {string.Join("", batchRequests)} + "; + + // 發送批次請求 + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(parkingConfig.ApiBase + "obix/batch"); + request.Method = "POST"; + request.Headers.Add("Authorization", "Basic " + encoded); + request.PreAuthenticate = true; + + byte[] requestData = Encoding.UTF8.GetBytes(batchRequestXml); + using (Stream reqStream = request.GetRequestStream()) + { + reqStream.Write(requestData, 0, requestData.Length); + } + + HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + var responseContent = new StreamReader(response.GetResponseStream()).ReadToEnd(); + // 檢查回應中是否有錯誤 + if (responseContent.Contains("(sql); - var T = types.Where(a => a.weather_type == "T").FirstOrDefault(); - var RbT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/T/set", T.get_value); - UpdatedNiagara("api_weateher", RbT, T.id); + var urlMapping = new Dictionary + { + { "T", "obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/T/set" }, + { "RH", "obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/RH/set" }, + { "PoP12h", "obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/PoP6h/set" }, + { "Wx", "obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/Wx/set" } + }; - var RH = types.Where(a => a.weather_type == "RH").FirstOrDefault(); - var RHT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/RH/set", RH.get_value); - UpdatedNiagara("api_weateher", RHT, RH.id); + // 建立批次請求 + var batchRequests = types + .Where(t => urlMapping.ContainsKey(t.weather_type)) + .Select(t => ( + url: obixApiConfig.ApiBase + urlMapping[t.weather_type], + value: t.get_value + )) + .ToList(); + + + // 呼叫批次請求 + var batchResponse = await ProcessBatchRequestAsync(obixApiConfig, batchRequests); + + // 解析回應 XML + var batchResponseXml = XDocument.Parse(batchResponse); + + var listElement = batchResponseXml.Descendants().FirstOrDefault(e => e.Name.LocalName == "list"); + + if (listElement == null) + { + throw new Exception("Batch response XML does not contain a 'list' element."); + } + + var childElements = listElement.Elements().ToList(); + + // 使用 urlMapping 的值反向找對應的 weather_type + for (int i = 0; i < childElements.Count; i++) + { + var tag = childElements[i].Name.LocalName; + var responseStr = childElements[i].ToString(); + var currentRequest = batchRequests[i]; + + // 找到當前 URL 在 urlMapping 中的 key (weather_type) + var weatherTypeKey = urlMapping.FirstOrDefault(x => currentRequest.url.Contains(x.Value)).Key; + + if (weatherTypeKey != null) + { + var weatherType = types.FirstOrDefault(t => t.weather_type == weatherTypeKey); + if (weatherType != null) + { + if (tag == "err") + { + UpdatedNiagara("api_weateher", responseStr, weatherType.id); + } + else + { + UpdatedNiagara("api_weateher", "success", weatherType.id); + } + } + else + { + logger.LogWarning($"No matching weather type found for key: {weatherTypeKey}"); + } + } + else + { + logger.LogWarning($"No matching URL found for request: {currentRequest.url}"); + } + } - var PoP12h = types.Where(a => a.weather_type == "PoP12h").FirstOrDefault(); - var PoP12hT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/PoP6h/set", PoP12h.get_value); - UpdatedNiagara("api_weateher", PoP12hT, PoP12h.id); - var Wx = types.Where(a => a.weather_type == "Wx").FirstOrDefault(); - var WxT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/Wx/set", Wx.get_value); - UpdatedNiagara("api_weateher", WxT, Wx.id); await task_Detail.InsertWorkTime_End("WeatherAPI", "set_weather"); - logger.LogInformation($"set niagara weather value success"); + logger.LogInformation($"Set Niagara weather value success"); } catch (Exception ex) { - logger.LogInformation($"set niagara weather value fail"); - await task_Detail.WorkFail("WeatherAPI", "set_weather", ex.Message.ToString()); + logger.LogError($"Set Niagara weather value fail: {ex.Message}"); + await task_Detail.WorkFail("WeatherAPI", "set_weather", ex.Message); } } + // Niagara單次寫法 + //if (await task_Detail.GetNeedWorkTask("WeatherAPI", "set_weather")) + //{ + // try + // { + // await task_Detail.InsertWorkTime("WeatherAPI", "set_weather"); + // var sql = @$"SELECT + // id, + // weather_type, + // get_value + // FROM api_weateher + // where id in (select MAX(id) from api_weateher where start_time < NOW() group by weather_type) + // order by start_time desc"; + // var types = await backendRepository.GetAllAsync(sql); + // var T = types.Where(a => a.weather_type == "T").FirstOrDefault(); + // var RbT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/T/set", T.get_value); + // UpdatedNiagara("api_weateher", RbT, T.id); + + // var RH = types.Where(a => a.weather_type == "RH").FirstOrDefault(); + // var RHT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/RH/set", RH.get_value); + // UpdatedNiagara("api_weateher", RHT, RH.id); + + // var PoP12h = types.Where(a => a.weather_type == "PoP12h").FirstOrDefault(); + // var PoP12hT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/PoP6h/set", PoP12h.get_value); + // UpdatedNiagara("api_weateher", PoP12hT, PoP12h.id); + + // var Wx = types.Where(a => a.weather_type == "Wx").FirstOrDefault(); + // var WxT = Fetch_PostWithJSONFormat($@"{obixApiConfig.ApiBase}obix/config/Arena/D2/CWB/L110/OPD/D2_CWB_L110_OPD_element/Wx/set", Wx.get_value); + // UpdatedNiagara("api_weateher", WxT, Wx.id); + // await task_Detail.InsertWorkTime_End("WeatherAPI", "set_weather"); + // logger.LogInformation($"set niagara weather value success"); + // } + // catch (Exception ex) + // { + // logger.LogInformation($"set niagara weather value fail"); + // await task_Detail.WorkFail("WeatherAPI", "set_weather", ex.Message.ToString()); + // } + //} } catch (Exception exception) { @@ -737,6 +836,51 @@ namespace BackendWorkerService.Quartz.Jobs return rint; } + public async Task ProcessBatchRequestAsync(ObixApiConfig obixApiConfig, List<(string url, string value)> batchRequests) + { + try + { + + var batchRequestData = new StringBuilder(); + string authInfo = Convert.ToBase64String(Encoding.Default.GetBytes($"{obixApiConfig.UserName}:{obixApiConfig.Password}")); + + // 組合批次請求的資料 + foreach (var request in batchRequests) + { + var jsonData = $""; + batchRequestData.AppendLine($"" + jsonData + ""); + } + + // 最終的批次請求資料 + var batchRequestXml = $@"{batchRequestData}"; + + // 建立 HTTP 請求 + var requestBacth = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/batch"); + requestBacth.Method = "POST"; + requestBacth.Headers.Add("Authorization", "Basic " + authInfo); + + // 寫入請求資料 + using (var streamWriter = new StreamWriter(requestBacth.GetRequestStream())) + { + streamWriter.Write(batchRequestXml); + } + + // 獲取回應 + using (var response = (HttpWebResponse)await requestBacth.GetResponseAsync()) + using (var streamReader = new StreamReader(response.GetResponseStream())) + { + return await streamReader.ReadToEndAsync(); + } + + } + catch (Exception) + { + + return "BatchRequestg失敗"; + } + } + + public async void UpdatedNiagara(string DBTableName, string ResponseStr, int CheckNumId) { try