using Backend.Models; using BackendWorkerService.Services.Implement; using Dapper; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Quartz; using Repository.BackendRepository.Interface; using Repository.Helper; 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 BackendWorkerService.Quartz.Jobs { [DisallowConcurrentExecution] class ArchiveElectricMeterDayJob : IJob { private readonly ILogger logger; private readonly IBackgroundServiceRepository backgroundServiceRepository; private readonly IBackgroundServiceMsSqlRepository backgroundServiceMsSqlRepository; protected readonly IDatabaseHelper _databaseHelper; private readonly ILogger loggers; public ArchiveElectricMeterDayJob( ILogger logger, IBackgroundServiceRepository backgroundServiceRepository, IBackgroundServiceMsSqlRepository backgroundServiceMySqlRepository, IDatabaseHelper databaseHelper, ILogger loggers, IBackendRepository backendRepository) { this.logger = logger; this.backgroundServiceRepository = backgroundServiceRepository; this.backgroundServiceMsSqlRepository = backgroundServiceMySqlRepository; this._databaseHelper = databaseHelper; this.loggers = loggers; } public async Task Execute(IJobExecutionContext context) { Task_Detail task_Detail = new Task_Detail(loggers, backgroundServiceRepository); string device_number = string.Empty; try { if (await task_Detail.GetNeedWorkTask("ArchiveElectricMeterDayJob", "All")) { await task_Detail.InsertWorkTime("ArchiveElectricMeterDayJob", "All", "任務開始"); EDFunction ed = new EDFunction(); XmlDocument xmlDocument = new XmlDocument(); ServicePointManager.DefaultConnectionLimit = 10; var sqlArchive = $@"SELECT system_value as Value, system_key as Name FROM variable WHERE deleted = 0 AND system_type = 'archiveConfig'"; var saveToMSDB = await backgroundServiceRepository.GetOneAsync("select system_value from variable where system_type = 'save_to_ms_db' and deleted = 0"); var variableArchive = await backgroundServiceRepository.GetAllAsync(sqlArchive); var electricMeterGuid = variableArchive.Where(x => x.Name == "ElectricMeterGuid").Select(x => x.Value).FirstOrDefault(); var waterMeterGuid = variableArchive.Where(x => x.Name == "WaterMeterGuid").Select(x => x.Value).FirstOrDefault(); string station = string.Empty; string tagQuantity = await backgroundServiceRepository.GetOneAsync("select system_value from variable where system_type = 'obixConfig' and system_key = 'tag_quantity' and deleted = 0;"); #region http variable HttpWebRequest archiveRequest = null; HttpWebResponse archiveResponse = null; string archiveResponseContent = null; string archiveJson = null; JObject archiveJsonResult = new JObject(); #endregion #region 找出所有電錶設備 var sWhere = "deleted = 0 AND device_name_tag = @sub_system_guid"; var electricMeters = await backgroundServiceRepository.GetAllAsync("device", sWhere, new { sub_system_guid = electricMeterGuid }); var waterMeters = await backgroundServiceRepository.GetAllAsync("device", sWhere, new { sub_system_guid = waterMeterGuid }); #endregion 找出所有電錶設備 #region 找出所有電錶系統的點位 var sPointWhere = "is_needArchive = 1 and deleted = 0 AND device_name_tag = @sub_system_guid"; var electricPoints = await backgroundServiceRepository.GetAllAsync("device_item", sPointWhere, new { sub_system_guid = electricMeterGuid }); var waterPoints = await backgroundServiceRepository.GetAllAsync("device_item", sPointWhere, new { sub_system_guid = waterMeterGuid }); #endregion 找出所有電錶系統的點位 #region 組合出所有電錶設備點位 List electricDeviceNumberPoints = new List(); foreach (var electricMeter in electricMeters) { foreach (var point in electricPoints) { if (electricMeter.device_building_tag == point.device_building_tag) { DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint(); deviceNumberPoint.DeviceNumber = electricMeter.Device_number; deviceNumberPoint.Point = point.points; deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", electricMeter.Device_number, point.points); deviceNumberPoint.archive_lastDate = electricMeter.archive_lastDate; electricDeviceNumberPoints.Add(deviceNumberPoint); } } } #endregion 組合出所有電錶設備點位 #region 組合出所有水錶設備點位 List waterDeviceNumberPoints = new List(); foreach (var waterMeter in waterMeters) { foreach (var point in waterPoints) { if (waterMeter.device_building_tag == point.device_building_tag) { DeviceNumberPoint deviceNumberPoint = new DeviceNumberPoint(); deviceNumberPoint.DeviceNumber = waterMeter.Device_number; deviceNumberPoint.Point = point.points; deviceNumberPoint.FullDeviceNumberPoint = string.Format("{0}_{1}", waterMeter.Device_number, point.points); deviceNumberPoint.archive_lastDate = waterMeter.archive_lastDate; waterDeviceNumberPoints.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 天歸檔 if (await task_Detail.GetNeedWorkTask("ArchiveElectricMeterDayJob", "Day")) { try { await task_Detail.InsertWorkTime("ArchiveElectricMeterDayJob", "Day", "水電表天任務開始"); //var preDay = now.AddDays(-1); //取得前一天 //var dbDateName = preDay.Year.ToString().PadLeft(4, '0') + preDay.Month.ToString().PadLeft(2, '0'); //var startTimestamp = string.Format("{0}T00:00:00.000+08:00", preDay.ToString("yyyy-MM-dd")); //var endTimestamp = string.Format("{0}T23:59:59.000+08:00", preDay.ToString("yyyy-MM-dd")); //var historyQueryFilter = $@" // // // // "; #region 從前次 成功日期到昨天為止 var preDay = now.AddDays(-1); //取得前一天 var dbDateName = preDay.Year.ToString().PadLeft(4, '0') + preDay.Month.ToString().PadLeft(2, '0'); #endregion //Stopwatch stopWatch = new Stopwatch(); //stopWatch.Start(); //抓取每個設備的資料 List> electericArchiveDayRawDatas = new List>(); List> waterArchiveDayRawDatas = new List>(); foreach (var deviceNumberPoint in electricDeviceNumberPoints) { var startDay = deviceNumberPoint.archive_lastDate.ToString("yyyy-MM-dd"); var endDay = System.DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd"); foreach (DateTime day in EachDay(startDay, endDay)) { var sDay = string.Format("{0}T00:00:00.000+08:00", day.ToString("yyyy-MM-dd").Replace(" ", "T")); var eDay = string.Format("{0}T00:15:00.000+08:00", day.AddDays(1).ToString("yyyy-MM-dd").Replace(" ", "T")); string historyQueryFilter = $@" "; device_number = deviceNumberPoint.FullDeviceNumberPoint; if (tagQuantity.Equals("5")) station = await backgroundServiceRepository.GetOneAsync($@"select parent_path from import_niagara_item_history where device_building_tag = '{device_number.Split("_")[0]}' and device_floor_tag = '{device_number.Split("_")[2]}' and device_name_tag = '{device_number.Split("_")[1]}' and device_point_name = '{device_number.Split("_")[5]}'"); else station = backgroundServiceRepository.GetOneAsync($@"select parent_path from import_niagara_item_history where device_building_tag = '{device_number.Split("_")[1].Replace("$3", "")}' and device_system_tag = '{device_number.Split("_")[2]}' and device_name_tag = '{device_number.Split("_")[3]}' and device_floor_tag = '{device_number.Split("_")[4]}' and device_master_tag = '{device_number.Split("_")[5]}' and device_last_name_tag = '{device_number.Split("_")[6]}' and device_serial_tag = '{device_number.Split("_")[7]}' and device_point_name = '{device_number.Split("_")[8]}'").Result; archiveRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/{station}/{deviceNumberPoint.FullDeviceNumberPoint.Replace("$3", "")}/~historyRollup/"); //HttpWebRequest archiveDayRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/{station}/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/"); archiveRequest.Method = "POST"; archiveRequest.Headers.Add("Authorization", "Basic " + encoded); archiveRequest.PreAuthenticate = true; byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter); using (Stream reqStream = archiveRequest.GetRequestStream()) { reqStream.Write(byteArray, 0, byteArray.Length); } archiveResponse = (HttpWebResponse)archiveRequest.GetResponse(); archiveResponseContent = new StreamReader(archiveResponse.GetResponseStream()).ReadToEnd(); archiveResponse.Dispose(); archiveResponse.Close(); xmlDocument.LoadXml(archiveResponseContent); archiveJson = JsonConvert.SerializeXmlNode(xmlDocument); archiveJsonResult = (JObject)JsonConvert.DeserializeObject(archiveJson); if (archiveJsonResult.ContainsKey("err")) //抓取錯誤 { //logger.LogError("【ArchiveElectricMeterDayJob】【天歸檔】【取得資料失敗】"); //logger.LogError("【ArchiveElectricMeterDayJob】【天歸檔】【取得資料失敗】[錯誤內容]:{0}", archiveDayJsonResult); Dictionary archiveDayRawData = new Dictionary(); archiveDayRawData.Add("@device_number", deviceNumberPoint.DeviceNumber); archiveDayRawData.Add("@point", deviceNumberPoint.Point); archiveDayRawData.Add("@start_timestamp", sDay.Replace("T", " ").Substring(0, 19)); archiveDayRawData.Add("@end_timestamp", eDay.Replace("T", " ").Substring(0, 19)); archiveDayRawData.Add("@is_complete", 0); archiveDayRawData.Add("@repeat_times", 0); archiveDayRawData.Add("@fail_reason", archiveJson); archiveDayRawData.Add("@count_rawdata", 0); archiveDayRawData.Add("@min_rawdata", 0); archiveDayRawData.Add("@max_rawdata", 0); archiveDayRawData.Add("@avg_rawdata", 0); archiveDayRawData.Add("@sum_rawdata", 0); archiveDayRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); electericArchiveDayRawDatas.Add(archiveDayRawData); } if (archiveJsonResult.ContainsKey("obj")) //表示可以讀取到內容 { var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveJsonResult); if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0) { electericArchiveDayRawDatas.AddRange(ArrangeRawDatas); } } } } foreach (var deviceNumberPoint in waterDeviceNumberPoints) { var startDay = deviceNumberPoint.archive_lastDate.ToString("yyyy-MM-dd"); var endDay = System.DateTime.Now.ToString("yyyy-MM-dd"); foreach (DateTime day in EachDay(startDay, endDay)) { var sDay = string.Format("{0}T00:00:00.000+08:00", day.ToString("yyyy-MM-dd").Replace(" ", "T")); var eDay = string.Format("{0}T00:15:00.000+08:00", day.AddDays(1).ToString("yyyy-MM-dd").Replace(" ", "T")); string historyQueryFilter = $@" "; device_number = deviceNumberPoint.FullDeviceNumberPoint; if (tagQuantity.Equals("5")) station = await backgroundServiceRepository.GetOneAsync($@"select parent_path from import_niagara_item_history where device_building_tag = '{device_number.Split("_")[0]}' and device_floor_tag = '{device_number.Split("_")[2]}' and device_name_tag = '{device_number.Split("_")[1]}' and device_point_name = '{device_number.Split("_")[5]}'"); else station = backgroundServiceRepository.GetOneAsync($@"select parent_path from import_niagara_item_history where device_building_tag = '{device_number.Split("_")[1].Replace("$3", "")}' and device_system_tag = '{device_number.Split("_")[2]}' and device_name_tag = '{device_number.Split("_")[3]}' and device_floor_tag = '{device_number.Split("_")[4]}' and device_master_tag = '{device_number.Split("_")[5]}' and device_last_name_tag = '{device_number.Split("_")[6]}' and device_serial_tag = '{device_number.Split("_")[7]}' and device_point_name = '{device_number.Split("_")[8]}'").Result; archiveRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/{station}/{deviceNumberPoint.FullDeviceNumberPoint.Replace("$3", "")}/~historyRollup/"); //HttpWebRequest archiveDayRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/{station}/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/"); archiveRequest.Method = "POST"; archiveRequest.Headers.Add("Authorization", "Basic " + encoded); archiveRequest.PreAuthenticate = true; byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter); using (Stream reqStream = archiveRequest.GetRequestStream()) { reqStream.Write(byteArray, 0, byteArray.Length); } archiveResponse = (HttpWebResponse)archiveRequest.GetResponse(); archiveResponseContent = new StreamReader(archiveResponse.GetResponseStream()).ReadToEnd(); archiveResponse.Dispose(); archiveResponse.Close(); xmlDocument.LoadXml(archiveResponseContent); archiveJson = JsonConvert.SerializeXmlNode(xmlDocument); archiveJsonResult = (JObject)JsonConvert.DeserializeObject(archiveJson); if (archiveJsonResult.ContainsKey("err")) //抓取錯誤 { //logger.LogError("【ArchiveElectricMeterDayJob】【天歸檔】【取得資料失敗】"); //logger.LogError("【ArchiveElectricMeterDayJob】【天歸檔】【取得資料失敗】[錯誤內容]:{0}", archiveDayJsonResult); Dictionary archiveDayRawData = new Dictionary(); archiveDayRawData.Add("@device_number", deviceNumberPoint.DeviceNumber); archiveDayRawData.Add("@point", deviceNumberPoint.Point); archiveDayRawData.Add("@start_timestamp", sDay.Replace("T", " ").Substring(0, 19)); archiveDayRawData.Add("@end_timestamp", eDay.Replace("T", " ").Substring(0, 19)); archiveDayRawData.Add("@is_complete", 0); archiveDayRawData.Add("@repeat_times", 0); archiveDayRawData.Add("@fail_reason", archiveJson); archiveDayRawData.Add("@count_rawdata", 0); archiveDayRawData.Add("@min_rawdata", 0); archiveDayRawData.Add("@max_rawdata", 0); archiveDayRawData.Add("@avg_rawdata", 0); archiveDayRawData.Add("@sum_rawdata", 0); archiveDayRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); waterArchiveDayRawDatas.Add(archiveDayRawData); } if (archiveJsonResult.ContainsKey("obj")) //表示可以讀取到內容 { var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveJsonResult); if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0) { waterArchiveDayRawDatas.AddRange(ArrangeRawDatas); } } } } //stopWatch.Stop(); //logger.LogInformation("【ArchiveElectricMeterDayJob】【天歸檔】【效能檢驗】[取得資料花費時間]{0} 毫秒", stopWatch.ElapsedMilliseconds); if (electericArchiveDayRawDatas.Count() > 0) { var sql = $@"CREATE TABLE IF NOT EXISTS `archive_electric_water_meter_day_{dbDateName}` ( `device_number` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `point` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `start_timestamp` datetime(6) NOT NULL, `end_timestamp` datetime(6) NULL DEFAULT NULL, `count_rawdata` int(11) NULL DEFAULT NULL, `min_rawdata` decimal(15, 3) NULL DEFAULT NULL, `max_rawdata` decimal(15, 3) NULL DEFAULT NULL, `sub_result` decimal(15, 3) NULL DEFAULT NULL, `avg_rawdata` decimal(15, 3) NULL DEFAULT NULL, `sum_rawdata` decimal(15, 3) NULL DEFAULT NULL, `is_complete` tinyint(3) UNSIGNED NULL DEFAULT NULL COMMENT '是否完成,0:未完成 1:完成', `repeat_times` int(11) NULL DEFAULT 0 COMMENT '重複次數', `fail_reason` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '失敗原因', `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime(6) NULL DEFAULT NULL, PRIMARY KEY (`device_number`, `point`, `start_timestamp`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; SET FOREIGN_KEY_CHECKS = 1; UPDATE archive_electric_water_meter_day_{dbDateName} SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, sub_result = @max_rawdata - @min_rawdata, avg_rawdata = @avg_rawdata, sum_rawdata = @sum_rawdata, is_complete = @is_complete, repeat_times = @repeat_times, fail_reason = @fail_reason, updated_at = @updated_at WHERE device_number = @device_number AND point = @point AND start_timestamp = @start_timestamp; INSERT INTO archive_electric_water_meter_day_{dbDateName} ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, sub_result, avg_rawdata, sum_rawdata, is_complete, repeat_times, fail_reason) SELECT @device_number, @point, @start_timestamp, @end_timestamp, @count_rawdata, @min_rawdata, @max_rawdata, @max_rawdata - @min_rawdata, @avg_rawdata, @sum_rawdata, @is_complete, @repeat_times, @fail_reason WHERE ROW_COUNT() = 0; update device set archive_lastDate = @start_timestamp, archive_lastActionDate = @updated_at where device_number = @device_number;"; //archive_lastDate 前次完成時間 ,archive_lastActionDate 本次作業時間 var mySql = $@"BEGIN TRANSACTION; IF OBJECT_ID(N'dbo.archive_electric_water_meter_day_{dbDateName}', N'U') is null BEGIN CREATE TABLE [dbo].[archive_electric_water_meter_day_{dbDateName}]( [device_number] [varchar](50) NOT NULL, [point] [varchar](20) NOT NULL, [start_timestamp] [datetime] NOT NULL, [end_timestamp] [datetime] NULL, [count_rawdata] [int] NULL, [min_rawdata] [decimal](15, 3) NULL, [max_rawdata] [decimal](15, 3) NULL, [sub_result] [decimal](15, 3) NULL, [avg_rawdata] [decimal](15, 3) NULL, [sum_rawdata] [decimal](15, 3) NULL, [is_complete] [tinyint] NULL, [repeat_times] [int] NULL, [fail_reason] [nvarchar](max) NULL, [created_at] [datetime] NULL, [updated_at] [datetime] NULL, CONSTRAINT [PK_archive_electric_water_meter_day_{dbDateName}] PRIMARY KEY CLUSTERED ( [device_number] ASC, [point] ASC, [start_timestamp] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] ALTER TABLE [dbo].[archive_electric_water_meter_day_{dbDateName}] ADD CONSTRAINT [DF_archive_electric_water_meter_day_{dbDateName}_repeat_times] DEFAULT ((0)) FOR [repeat_times] ALTER TABLE [dbo].[archive_electric_water_meter_day_{dbDateName}] ADD CONSTRAINT [DF_archive_electric_water_meter_day_{dbDateName}_created_at] DEFAULT (getdate()) FOR [created_at] ALTER TABLE [dbo].[archive_electric_water_meter_day_{dbDateName}] ADD CONSTRAINT [DF_archive_electric_water_meter_day_{dbDateName}_updated_at] DEFAULT (NULL) FOR [updated_at] EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否完成,0:未完成 1:完成' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'archive_electric_water_meter_day_{dbDateName}', @level2type=N'COLUMN',@level2name=N'is_complete' EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'重複次數' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'archive_electric_water_meter_day_{dbDateName}', @level2type=N'COLUMN',@level2name=N'repeat_times' EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'失敗原因' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'archive_electric_water_meter_day_{dbDateName}', @level2type=N'COLUMN',@level2name=N'fail_reason' END UPDATE archive_electric_water_meter_day_{dbDateName} SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, sub_result = @max_rawdata - @min_rawdata, avg_rawdata = @avg_rawdata, sum_rawdata = @sum_rawdata, is_complete = @is_complete, repeat_times = @repeat_times, fail_reason = @fail_reason, updated_at = @updated_at WHERE device_number = @device_number AND point = @point AND start_timestamp = @start_timestamp; IF @@ROWCOUNT = 0 BEGIN INSERT INTO archive_electric_water_meter_day_{dbDateName} ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, sub_result, avg_rawdata, sum_rawdata, is_complete, repeat_times, fail_reason) VALUES ( @device_number, @point, @start_timestamp, @end_timestamp, @count_rawdata, @min_rawdata, @max_rawdata, @max_rawdata - @min_rawdata, @avg_rawdata, @sum_rawdata, @is_complete, @repeat_times, @fail_reason) END COMMIT TRANSACTION;"; await backgroundServiceRepository.ExecuteSql(sql, electericArchiveDayRawDatas); if (!string.IsNullOrEmpty(saveToMSDB) && saveToMSDB == "1") { await backgroundServiceMsSqlRepository.ExecuteSql(mySql, electericArchiveDayRawDatas); } } if (waterArchiveDayRawDatas.Count() > 0) { var sql = $@" CREATE TABLE IF NOT EXISTS `archive_electric_water_meter_day_{dbDateName}` ( `device_number` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `point` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `start_timestamp` datetime(6) NOT NULL, `end_timestamp` datetime(6) NULL DEFAULT NULL, `count_rawdata` int(11) NULL DEFAULT NULL, `min_rawdata` decimal(15, 3) NULL DEFAULT NULL, `max_rawdata` decimal(15, 3) NULL DEFAULT NULL, `sub_result` decimal(15, 3) NULL DEFAULT NULL, `avg_rawdata` decimal(15, 3) NULL DEFAULT NULL, `sum_rawdata` decimal(15, 3) NULL DEFAULT NULL, `is_complete` tinyint(3) UNSIGNED NULL DEFAULT NULL COMMENT '是否完成,0:未完成 1:完成', `repeat_times` int(11) NULL DEFAULT 0 COMMENT '重複次數', `fail_reason` varchar(4000) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '失敗原因', `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime(6) NULL DEFAULT NULL, PRIMARY KEY (`device_number`, `point`, `start_timestamp`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = DYNAMIC; UPDATE archive_electric_water_meter_day_{dbDateName} SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, sub_result = @max_rawdata - @min_rawdata, avg_rawdata = @avg_rawdata, sum_rawdata = @sum_rawdata, is_complete = @is_complete, repeat_times = @repeat_times, fail_reason = @fail_reason, updated_at = @updated_at WHERE device_number = @device_number AND point = @point AND start_timestamp = @start_timestamp; INSERT INTO archive_electric_water_meter_day_{dbDateName} ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, sub_result, avg_rawdata, sum_rawdata, is_complete, repeat_times, fail_reason) SELECT @device_number, @point, @start_timestamp, @end_timestamp, @count_rawdata, @min_rawdata, @max_rawdata, @max_rawdata - @min_rawdata, @avg_rawdata, @sum_rawdata, @is_complete, @repeat_times, @fail_reason WHERE ROW_COUNT() = 0; update device set archive_lastDate = @start_timestamp, archive_lastActionDate = @updated_at where device_number = @device_number;"; //archive_lastDate 前次完成時間 ,archive_lastActionDate 本次作業時間 var mySql = $@"BEGIN TRANSACTION; IF OBJECT_ID(N'dbo.archive_electric_water_meter_day_{dbDateName}', N'U') is null BEGIN CREATE TABLE [dbo].[archive_electric_water_meter_day_{dbDateName}]( [device_number] [varchar](50) NOT NULL, [point] [varchar](20) NOT NULL, [start_timestamp] [datetime] NOT NULL, [end_timestamp] [datetime] NULL, [count_rawdata] [int] NULL, [min_rawdata] [decimal](15, 3) NULL, [max_rawdata] [decimal](15, 3) NULL, [sub_result] [decimal](15, 3) NULL, [avg_rawdata] [decimal](15, 3) NULL, [sum_rawdata] [decimal](15, 3) NULL, [is_complete] [tinyint] NULL, [repeat_times] [int] NULL, [fail_reason] [nvarchar](max) NULL, [created_at] [datetime] NULL, [updated_at] [datetime] NULL, CONSTRAINT [PK_archive_electric_water_meter_day_{dbDateName}] PRIMARY KEY CLUSTERED ( [device_number] ASC, [point] ASC, [start_timestamp] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] ALTER TABLE [dbo].[archive_electric_water_meter_day_{dbDateName}] ADD CONSTRAINT [DF_archive_electric_water_meter_day_{dbDateName}_repeat_times] DEFAULT ((0)) FOR [repeat_times] ALTER TABLE [dbo].[archive_electric_water_meter_day_{dbDateName}] ADD CONSTRAINT [DF_archive_electric_water_meter_day_{dbDateName}_created_at] DEFAULT (getdate()) FOR [created_at] ALTER TABLE [dbo].[archive_electric_water_meter_day_{dbDateName}] ADD CONSTRAINT [DF_archive_electric_water_meter_day_{dbDateName}_updated_at] DEFAULT (NULL) FOR [updated_at] EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'是否完成,0:未完成 1:完成' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'archive_electric_water_meter_day_{dbDateName}', @level2type=N'COLUMN',@level2name=N'is_complete' EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'重複次數' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'archive_electric_water_meter_day_{dbDateName}', @level2type=N'COLUMN',@level2name=N'repeat_times' EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'失敗原因' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'archive_electric_water_meter_day_{dbDateName}', @level2type=N'COLUMN',@level2name=N'fail_reason' END UPDATE archive_electric_water_meter_day_{dbDateName} SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, sub_result = @max_rawdata - @min_rawdata, avg_rawdata = @avg_rawdata, sum_rawdata = @sum_rawdata, is_complete = @is_complete, repeat_times = @repeat_times, fail_reason = @fail_reason, updated_at = @updated_at WHERE device_number = @device_number AND point = @point AND start_timestamp = @start_timestamp; IF @@ROWCOUNT = 0 BEGIN INSERT INTO archive_electric_water_meter_day_{dbDateName} ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, sub_result, avg_rawdata, sum_rawdata, is_complete, repeat_times, fail_reason) VALUES ( @device_number, @point, @start_timestamp, @end_timestamp, @count_rawdata, @min_rawdata, @max_rawdata, @max_rawdata - @min_rawdata, @avg_rawdata, @sum_rawdata, @is_complete, @repeat_times, @fail_reason) END COMMIT TRANSACTION;"; await backgroundServiceRepository.ExecuteSql(sql, waterArchiveDayRawDatas); if (!string.IsNullOrEmpty(saveToMSDB) && saveToMSDB == "1") { await backgroundServiceMsSqlRepository.ExecuteSql(mySql, waterArchiveDayRawDatas); } } await task_Detail.InsertWorkTime_End("ArchiveElectricMeterDayJob", "Day", "任務完成"); } catch (Exception exception) { await task_Detail.WorkFail("ArchiveElectricMeterDayJob", "Day", exception.ToString()); logger.LogError("【ArchiveElectricMeterDayJob】【天歸檔】【任務失敗】"); logger.LogError("【ArchiveElectricMeterDayJob】【天歸檔】【任務失敗】[Exception]:{0}", exception.ToString()); logger.LogError(await backgroundServiceMsSqlRepository.GetDbAllString()); } finally { if (archiveResponse != null) { archiveResponse.Dispose(); archiveResponse.Close(); } } } #endregion 天歸檔 #region 週歸檔 //if (await task_Detail.GetNeedWorkTask("ArchiveElectricMeterDayJob", "Week")) //{ // try // { // await task_Detail.InsertWorkTime("ArchiveElectricMeterDayJob", "Week", "水電表周任務開始"); // int week = Convert.ToInt32(now.DayOfWeek); // week = week == 0 ? 7 : week; // var startTimestamp = string.Format("{0}T00:00:00.000+08:00", now.AddDays(1 - week).ToString("yyyy-MM-dd")); // var endTimestamp = string.Format("{0}T23:59:59.000+08:00", now.AddDays(7 - week).ToString("yyyy-MM-dd")); // var historyQueryFilter = $@" // // // // "; // //Stopwatch stopWatch = new Stopwatch(); // //stopWatch.Start(); // //抓取每個設備的資料 // List> electricArchiveWeekRawDatas = new List>(); // List> waterArchiveWeekRawDatas = new List>(); // foreach (var deviceNumberPoint in electricDeviceNumberPoints) // { // if (tagQuantity.Equals("5")) // station = await backgroundServiceRepository.GetOneAsync($@"select parent_path from import_niagara_item_history // where device_building_tag = '{device_number.Split("_")[0]}' and device_floor_tag = '{device_number.Split("_")[2]}' // and device_name_tag = '{device_number.Split("_")[1]}' and device_point_name = '{device_number.Split("_")[5]}'"); // else // station = backgroundServiceRepository.GetOneAsync($@"select parent_path from import_niagara_item_history // where device_building_tag = '{device_number.Split("_")[1].Replace("$3", "")}' and // device_system_tag = '{device_number.Split("_")[2]}' and device_name_tag = '{device_number.Split("_")[3]}' // and device_floor_tag = '{device_number.Split("_")[4]}' and device_master_tag = '{device_number.Split("_")[5]}' // and device_last_name_tag = '{device_number.Split("_")[6]}' and device_serial_tag = '{device_number.Split("_")[7]}' // and device_point_name = '{device_number.Split("_")[8]}'").Result; // device_number = deviceNumberPoint.FullDeviceNumberPoint; // archiveRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/{station}/{deviceNumberPoint.FullDeviceNumberPoint.Replace("$3", "")}/~historyRollup/"); // //HttpWebRequest archiveWeekRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/{station}/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/"); // archiveRequest.Method = "POST"; // archiveRequest.Headers.Add("Authorization", "Basic " + encoded); // archiveRequest.PreAuthenticate = true; // byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter); // using (Stream reqStream = archiveRequest.GetRequestStream()) // { // reqStream.Write(byteArray, 0, byteArray.Length); // } // archiveResponse = (HttpWebResponse)archiveRequest.GetResponse(); // archiveResponseContent = new StreamReader(archiveResponse.GetResponseStream()).ReadToEnd(); // archiveResponse.Dispose(); // archiveResponse.Close(); // xmlDocument.LoadXml(archiveResponseContent); // archiveJson = JsonConvert.SerializeXmlNode(xmlDocument); // archiveJsonResult = (JObject)JsonConvert.DeserializeObject(archiveJson); // if (archiveJsonResult.ContainsKey("err")) //抓取錯誤 // { // //logger.LogError("【ArchiveElectricMeterDayJob】【週歸檔】【取得資料失敗】"); // //logger.LogError("【ArchiveElectricMeterDayJob】【週歸檔】【取得資料失敗】[錯誤內容]:{0}", archiveWeekJsonResult); // Dictionary archiveWeekRawData = new Dictionary(); // archiveWeekRawData.Add("@device_number", deviceNumberPoint.DeviceNumber); // archiveWeekRawData.Add("@point", deviceNumberPoint.Point); // archiveWeekRawData.Add("@start_timestamp", startTimestamp.Replace("T", " ").Substring(0, 19)); // archiveWeekRawData.Add("@end_timestamp", endTimestamp.Replace("T", " ").Substring(0, 19)); // archiveWeekRawData.Add("@is_complete", 0); // archiveWeekRawData.Add("@repeat_times", 0); // archiveWeekRawData.Add("@fail_reason", archiveJson); // archiveWeekRawData.Add("@count_rawdata", 0); // archiveWeekRawData.Add("@min_rawdata", 0); // archiveWeekRawData.Add("@max_rawdata", 0); // archiveWeekRawData.Add("@avg_rawdata", 0); // archiveWeekRawData.Add("@sum_rawdata", 0); // archiveWeekRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); // electricArchiveWeekRawDatas.Add(archiveWeekRawData); // } // if (archiveJsonResult.ContainsKey("obj")) //表示可以讀取到內容 // { // var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveJsonResult); // if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0) // { // electricArchiveWeekRawDatas.AddRange(ArrangeRawDatas); // } // } // } // foreach (var deviceNumberPoint in waterDeviceNumberPoints) // { // device_number = deviceNumberPoint.FullDeviceNumberPoint; // if (tagQuantity.Equals("5")) // station = await backgroundServiceRepository.GetOneAsync($@"select parent_path from import_niagara_item_history // where device_building_tag = '{device_number.Split("_")[0]}' and device_floor_tag = '{device_number.Split("_")[2]}' // and device_name_tag = '{device_number.Split("_")[1]}' and device_point_name = '{device_number.Split("_")[5]}'"); // else // station = backgroundServiceRepository.GetOneAsync($@"select parent_path from import_niagara_item_history // where device_building_tag = '{device_number.Split("_")[1].Replace("$3", "")}' and // device_system_tag = '{device_number.Split("_")[2]}' and device_name_tag = '{device_number.Split("_")[3]}' // and device_floor_tag = '{device_number.Split("_")[4]}' and device_master_tag = '{device_number.Split("_")[5]}' // and device_last_name_tag = '{device_number.Split("_")[6]}' and device_serial_tag = '{device_number.Split("_")[7]}' // and device_point_name = '{device_number.Split("_")[8]}'").Result; // archiveRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/{station}/{deviceNumberPoint.FullDeviceNumberPoint.Replace("$3", "")}/~historyRollup/"); // //HttpWebRequest archiveWeekRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/{station}/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/"); // archiveRequest.Method = "POST"; // archiveRequest.Headers.Add("Authorization", "Basic " + encoded); // archiveRequest.PreAuthenticate = true; // byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter); // using (Stream reqStream = archiveRequest.GetRequestStream()) // { // reqStream.Write(byteArray, 0, byteArray.Length); // } // archiveResponse = (HttpWebResponse)archiveRequest.GetResponse(); // archiveResponseContent = new StreamReader(archiveResponse.GetResponseStream()).ReadToEnd(); // archiveResponse.Dispose(); // archiveResponse.Close(); // xmlDocument.LoadXml(archiveResponseContent); // archiveJson = JsonConvert.SerializeXmlNode(xmlDocument); // archiveJsonResult = (JObject)JsonConvert.DeserializeObject(archiveJson); // if (archiveJsonResult.ContainsKey("err")) //抓取錯誤 // { // //logger.LogError("【ArchiveElectricMeterDayJob】【週歸檔】【取得資料失敗】"); // //logger.LogError("【ArchiveElectricMeterDayJob】【週歸檔】【取得資料失敗】[錯誤內容]:{0}", archiveWeekJsonResult); // Dictionary archiveWeekRawData = new Dictionary(); // archiveWeekRawData.Add("@device_number", deviceNumberPoint.DeviceNumber); // archiveWeekRawData.Add("@point", deviceNumberPoint.Point); // archiveWeekRawData.Add("@start_timestamp", startTimestamp.Replace("T", " ").Substring(0, 19)); // archiveWeekRawData.Add("@end_timestamp", endTimestamp.Replace("T", " ").Substring(0, 19)); // archiveWeekRawData.Add("@is_complete", 0); // archiveWeekRawData.Add("@repeat_times", 0); // archiveWeekRawData.Add("@fail_reason", archiveJson); // archiveWeekRawData.Add("@count_rawdata", 0); // archiveWeekRawData.Add("@min_rawdata", 0); // archiveWeekRawData.Add("@max_rawdata", 0); // archiveWeekRawData.Add("@avg_rawdata", 0); // archiveWeekRawData.Add("@sum_rawdata", 0); // archiveWeekRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); // waterArchiveWeekRawDatas.Add(archiveWeekRawData); // } // if (archiveJsonResult.ContainsKey("obj")) //表示可以讀取到內容 // { // var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveJsonResult); // if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0) // { // waterArchiveWeekRawDatas.AddRange(ArrangeRawDatas); // } // } // } // //stopWatch.Stop(); // //logger.LogInformation("【ArchiveElectricMeterDayJob】【週歸檔】【效能檢驗】[取得資料花費時間]{0} 毫秒", stopWatch.ElapsedMilliseconds); // if (electricArchiveWeekRawDatas.Count() > 0) // { // var sql = $@" // UPDATE archive_electric_water_meter_week SET // count_rawdata = @count_rawdata, // min_rawdata = @min_rawdata, // max_rawdata = @max_rawdata, // sub_result = @max_rawdata - @min_rawdata, // avg_rawdata = @avg_rawdata, // sum_rawdata = @sum_rawdata, // is_complete = @is_complete, // repeat_times = @repeat_times, // fail_reason = @fail_reason, // updated_at = @updated_at // WHERE device_number = @device_number // AND point = @point // AND start_timestamp = @start_timestamp; // INSERT INTO archive_electric_water_meter_week ( // device_number, // point, // start_timestamp, // end_timestamp, // count_rawdata, // min_rawdata, // max_rawdata, // sub_result, // avg_rawdata, // sum_rawdata, // is_complete, // repeat_times, // fail_reason) // SELECT // @device_number, // @point, // @start_timestamp, // @end_timestamp, // @count_rawdata, // @min_rawdata, // @max_rawdata, // @max_rawdata - @min_rawdata, // @avg_rawdata, // @sum_rawdata, // @is_complete, // @repeat_times, // @fail_reason // WHERE ROW_COUNT() = 0; // "; // var mySql = $@"BEGIN TRANSACTION; // UPDATE archive_electric_water_meter_week SET // count_rawdata = @count_rawdata, // min_rawdata = @min_rawdata, // max_rawdata = @max_rawdata, // sub_result = @max_rawdata - @min_rawdata, // avg_rawdata = @avg_rawdata, // sum_rawdata = @sum_rawdata, // is_complete = @is_complete, // repeat_times = @repeat_times, // fail_reason = @fail_reason, // updated_at = @updated_at // WHERE device_number = @device_number // AND point = @point // AND start_timestamp = @start_timestamp; // IF @@ROWCOUNT = 0 // BEGIN // INSERT INTO archive_electric_water_meter_week ( // device_number, // point, // start_timestamp, // end_timestamp, // count_rawdata, // min_rawdata, // max_rawdata, // sub_result, // avg_rawdata, // sum_rawdata, // is_complete, // repeat_times, // fail_reason) // VALUES ( // @device_number, // @point, // @start_timestamp, // @end_timestamp, // @count_rawdata, // @min_rawdata, // @max_rawdata, // @max_rawdata - @min_rawdata, // @avg_rawdata, // @sum_rawdata, // @is_complete, // @repeat_times, // @fail_reason) // END // COMMIT TRANSACTION;"; // await backgroundServiceRepository.ExecuteSql(sql, electricArchiveWeekRawDatas); // if (!string.IsNullOrEmpty(saveToMSDB) && saveToMSDB == "1") // { // await backgroundServiceMsSqlRepository.ExecuteSql(mySql, electricArchiveWeekRawDatas); // } // } // if (waterArchiveWeekRawDatas.Count() > 0) // { // var sql = $@" // UPDATE archive_electric_water_meter_week SET // count_rawdata = @count_rawdata, // min_rawdata = @min_rawdata, // max_rawdata = @max_rawdata, // sub_result = @max_rawdata - @min_rawdata, // avg_rawdata = @avg_rawdata, // sum_rawdata = @sum_rawdata, // is_complete = @is_complete, // repeat_times = @repeat_times, // fail_reason = @fail_reason, // updated_at = @updated_at // WHERE device_number = @device_number // AND point = @point // AND start_timestamp = @start_timestamp; // INSERT INTO archive_electric_water_meter_week ( // device_number, // point, // start_timestamp, // end_timestamp, // count_rawdata, // min_rawdata, // max_rawdata, // sub_result, // avg_rawdata, // sum_rawdata, // is_complete, // repeat_times, // fail_reason) // SELECT // @device_number, // @point, // @start_timestamp, // @end_timestamp, // @count_rawdata, // @min_rawdata, // @max_rawdata, // @max_rawdata - @min_rawdata, // @avg_rawdata, // @sum_rawdata, // @is_complete, // @repeat_times, // @fail_reason // WHERE ROW_COUNT() = 0; // "; // var mySql = $@"BEGIN TRANSACTION; // UPDATE archive_electric_water_meter_week SET // count_rawdata = @count_rawdata, // min_rawdata = @min_rawdata, // max_rawdata = @max_rawdata, // sub_result = @max_rawdata - @min_rawdata, // avg_rawdata = @avg_rawdata, // sum_rawdata = @sum_rawdata, // is_complete = @is_complete, // repeat_times = @repeat_times, // fail_reason = @fail_reason, // updated_at = @updated_at // WHERE device_number = @device_number // AND point = @point // AND start_timestamp = @start_timestamp; // IF @@ROWCOUNT = 0 // BEGIN // INSERT INTO archive_electric_water_meter_week ( // device_number, // point, // start_timestamp, // end_timestamp, // count_rawdata, // min_rawdata, // max_rawdata, // sub_result, // avg_rawdata, // sum_rawdata, // is_complete, // repeat_times, // fail_reason) // VALUES ( // @device_number, // @point, // @start_timestamp, // @end_timestamp, // @count_rawdata, // @min_rawdata, // @max_rawdata, // @max_rawdata - @min_rawdata, // @avg_rawdata, // @sum_rawdata, // @is_complete, // @repeat_times, // @fail_reason) // END // COMMIT TRANSACTION;"; // await backgroundServiceRepository.ExecuteSql(sql, waterArchiveWeekRawDatas); // if (!string.IsNullOrEmpty(saveToMSDB) && saveToMSDB == "1") // { // await backgroundServiceMsSqlRepository.ExecuteSql(mySql, waterArchiveWeekRawDatas); // } // } // await task_Detail.InsertWorkTime_End("ArchiveElectricMeterDayJob", "Week", "任務完成"); // } // catch (Exception exception) // { // await task_Detail.WorkFail("ArchiveElectricMeterDayJob", "Week", exception.ToString()); // logger.LogError("【ArchiveElectricMeterDayJob】【週歸檔】【任務失敗】"); // logger.LogError("【ArchiveElectricMeterDayJob】【週歸檔】【任務失敗】[Exception]:{0}", exception.ToString()); // } // finally // { // if (archiveResponse != null) // { // archiveResponse.Dispose(); // archiveResponse.Close(); // } // } //} #endregion 週歸檔 #region 月歸檔 if (await task_Detail.GetNeedWorkTask("ArchiveElectricMeterDayJob", "Month")) { try { await task_Detail.InsertWorkTime("ArchiveElectricMeterDayJob", "Month", "水電表月任務開始"); var FirstDay = now.AddDays(-now.Day + 1); //var LastDay = now.AddMonths(1).AddDays(-now.AddMonths(1).Day); var LastDay = FirstDay.AddMonths(1); var dayInMonth = DateTime.DaysInMonth(now.Year, now.Month); var startTimestamp = string.Format("{0}T00:00:00.000+08:00", FirstDay.ToString("yyyy-MM-dd")); //var endTimestamp = string.Format("{0}T23:59:59.000+08:00", LastDay.ToString("yyyy-MM-dd")); var endTimestamp = string.Format("{0}T00:15:00.000+08:00", LastDay.ToString("yyyy-MM-dd")); // 240131 jay for dome var historyQueryFilter = $@" "; //Stopwatch stopWatch = new Stopwatch(); //stopWatch.Start(); //抓取每個設備的資料 List> electricArchiveMonthRawDatas = new List>(); List> waterArchiveMonthRawDatas = new List>(); foreach (var deviceNumberPoint in electricDeviceNumberPoints) { device_number = deviceNumberPoint.FullDeviceNumberPoint; if (tagQuantity.Equals("5")) station = await backgroundServiceRepository.GetOneAsync($@"select parent_path from import_niagara_item_history where device_building_tag = '{device_number.Split("_")[0]}' and device_floor_tag = '{device_number.Split("_")[2]}' and device_name_tag = '{device_number.Split("_")[1]}' and device_point_name = '{device_number.Split("_")[5]}'"); else station = backgroundServiceRepository.GetOneAsync($@"select parent_path from import_niagara_item_history where device_building_tag = '{device_number.Split("_")[1].Replace("$3", "")}' and device_system_tag = '{device_number.Split("_")[2]}' and device_name_tag = '{device_number.Split("_")[3]}' and device_floor_tag = '{device_number.Split("_")[4]}' and device_master_tag = '{device_number.Split("_")[5]}' and device_last_name_tag = '{device_number.Split("_")[6]}' and device_serial_tag = '{device_number.Split("_")[7]}' and device_point_name = '{device_number.Split("_")[8]}'").Result; archiveRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/{station}/{deviceNumberPoint.FullDeviceNumberPoint.Replace("$3", "")}/~historyRollup/"); //HttpWebRequest archiveMonthRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/{station}/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/"); archiveRequest.Method = "POST"; archiveRequest.Headers.Add("Authorization", "Basic " + encoded); archiveRequest.PreAuthenticate = true; byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter); using (Stream reqStream = archiveRequest.GetRequestStream()) { reqStream.Write(byteArray, 0, byteArray.Length); } archiveResponse = (HttpWebResponse)archiveRequest.GetResponse(); archiveResponseContent = new StreamReader(archiveResponse.GetResponseStream()).ReadToEnd(); archiveResponse.Dispose(); archiveResponse.Close(); xmlDocument.LoadXml(archiveResponseContent); archiveJson = JsonConvert.SerializeXmlNode(xmlDocument); archiveJsonResult = (JObject)JsonConvert.DeserializeObject(archiveJson); if (archiveJsonResult.ContainsKey("err")) //抓取錯誤 { //logger.LogError("【ArchiveElectricMeterDayJob】【月歸檔】【取得資料失敗】"); //logger.LogError("【ArchiveElectricMeterDayJob】【月歸檔】【取得資料失敗】[錯誤內容]:{0}", archiveMonthJsonResult); Dictionary archiveMonthRawData = new Dictionary(); archiveMonthRawData.Add("@device_number", deviceNumberPoint.DeviceNumber); archiveMonthRawData.Add("@point", deviceNumberPoint.Point); archiveMonthRawData.Add("@start_timestamp", startTimestamp.Replace("T", " ").Substring(0, 19)); archiveMonthRawData.Add("@end_timestamp", endTimestamp.Replace("T", " ").Substring(0, 19)); archiveMonthRawData.Add("@is_complete", 0); archiveMonthRawData.Add("@repeat_times", 0); archiveMonthRawData.Add("@fail_reason", archiveJson); archiveMonthRawData.Add("@count_rawdata", 0); archiveMonthRawData.Add("@min_rawdata", 0); archiveMonthRawData.Add("@max_rawdata", 0); archiveMonthRawData.Add("@avg_rawdata", 0); archiveMonthRawData.Add("@sum_rawdata", 0); archiveMonthRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); electricArchiveMonthRawDatas.Add(archiveMonthRawData); } if (archiveJsonResult.ContainsKey("obj")) //表示可以讀取到內容 { var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveJsonResult); if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0) { electricArchiveMonthRawDatas.AddRange(ArrangeRawDatas); } } } foreach (var deviceNumberPoint in waterDeviceNumberPoints) { device_number = deviceNumberPoint.FullDeviceNumberPoint; if (tagQuantity.Equals("5")) station = await backgroundServiceRepository.GetOneAsync($@"select parent_path from import_niagara_item_history where device_building_tag = '{device_number.Split("_")[0]}' and device_floor_tag = '{device_number.Split("_")[2]}' and device_name_tag = '{device_number.Split("_")[1]}' and device_point_name = '{device_number.Split("_")[5]}'"); else station = backgroundServiceRepository.GetOneAsync($@"select parent_path from import_niagara_item_history where device_building_tag = '{device_number.Split("_")[1].Replace("$3", "")}' and device_system_tag = '{device_number.Split("_")[2]}' and device_name_tag = '{device_number.Split("_")[3]}' and device_floor_tag = '{device_number.Split("_")[4]}' and device_master_tag = '{device_number.Split("_")[5]}' and device_last_name_tag = '{device_number.Split("_")[6]}' and device_serial_tag = '{device_number.Split("_")[7]}' and device_point_name = '{device_number.Split("_")[8]}'").Result; archiveRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/{station}/{deviceNumberPoint.FullDeviceNumberPoint.Replace("$3", "")}/~historyRollup/"); //HttpWebRequest archiveMonthRequest = (HttpWebRequest)WebRequest.Create($"{obixApiConfig.ApiBase}obix/histories/{station}/H_E1_B1F_MVCB_MVCBH_V1/~historyRollup/"); archiveRequest.Method = "POST"; archiveRequest.Headers.Add("Authorization", "Basic " + encoded); archiveRequest.PreAuthenticate = true; byte[] byteArray = Encoding.UTF8.GetBytes(historyQueryFilter); using (Stream reqStream = archiveRequest.GetRequestStream()) { reqStream.Write(byteArray, 0, byteArray.Length); } archiveResponse = (HttpWebResponse)archiveRequest.GetResponse(); archiveResponseContent = new StreamReader(archiveResponse.GetResponseStream()).ReadToEnd(); archiveResponse.Dispose(); archiveResponse.Close(); xmlDocument.LoadXml(archiveResponseContent); archiveJson = JsonConvert.SerializeXmlNode(xmlDocument); archiveJsonResult = (JObject)JsonConvert.DeserializeObject(archiveJson); if (archiveJsonResult.ContainsKey("err")) //抓取錯誤 { //logger.LogError("【ArchiveElectricMeterDayJob】【月歸檔】【取得資料失敗】"); //logger.LogError("【ArchiveElectricMeterDayJob】【月歸檔】【取得資料失敗】[錯誤內容]:{0}", archiveMonthJsonResult); Dictionary archiveMonthRawData = new Dictionary(); archiveMonthRawData.Add("@device_number", deviceNumberPoint.DeviceNumber); archiveMonthRawData.Add("@point", deviceNumberPoint.Point); archiveMonthRawData.Add("@start_timestamp", startTimestamp.Replace("T", " ").Substring(0, 19)); archiveMonthRawData.Add("@end_timestamp", endTimestamp.Replace("T", " ").Substring(0, 19)); archiveMonthRawData.Add("@is_complete", 0); archiveMonthRawData.Add("@repeat_times", 0); archiveMonthRawData.Add("@fail_reason", archiveJson); archiveMonthRawData.Add("@count_rawdata", 0); archiveMonthRawData.Add("@min_rawdata", 0); archiveMonthRawData.Add("@max_rawdata", 0); archiveMonthRawData.Add("@avg_rawdata", 0); archiveMonthRawData.Add("@sum_rawdata", 0); archiveMonthRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); waterArchiveMonthRawDatas.Add(archiveMonthRawData); } if (archiveJsonResult.ContainsKey("obj")) //表示可以讀取到內容 { var ArrangeRawDatas = ArrangeRawData(deviceNumberPoint, archiveJsonResult); if (ArrangeRawDatas != null && ArrangeRawDatas.Count() > 0) { waterArchiveMonthRawDatas.AddRange(ArrangeRawDatas); } } } //stopWatch.Stop(); //logger.LogInformation("【ArchiveElectricMeterDayJob】【月歸檔效能檢驗】[取得資料花費時間]{0} 毫秒", stopWatch.ElapsedMilliseconds); if (electricArchiveMonthRawDatas.Count() > 0) { var sql = $@" UPDATE archive_electric_water_meter_month SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, sub_result = @max_rawdata - @min_rawdata, avg_rawdata = @avg_rawdata, sum_rawdata = @sum_rawdata, is_complete = @is_complete, repeat_times = @repeat_times, fail_reason = @fail_reason, updated_at = @updated_at WHERE device_number = @device_number AND point = @point AND start_timestamp = @start_timestamp; INSERT INTO archive_electric_water_meter_month ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, sub_result, avg_rawdata, sum_rawdata, is_complete, repeat_times, fail_reason) SELECT @device_number, @point, @start_timestamp, @end_timestamp, @count_rawdata, @min_rawdata, @max_rawdata, @max_rawdata - @min_rawdata, @avg_rawdata, @sum_rawdata, @is_complete, @repeat_times, @fail_reason WHERE ROW_COUNT() = 0;"; var mySql = $@"BEGIN TRANSACTION; UPDATE archive_electric_water_meter_month SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, sub_result = @max_rawdata - @min_rawdata, avg_rawdata = @avg_rawdata, sum_rawdata = @sum_rawdata, is_complete = @is_complete, repeat_times = @repeat_times, fail_reason = @fail_reason, updated_at = @updated_at WHERE device_number = @device_number AND point = @point AND start_timestamp = @start_timestamp; IF @@ROWCOUNT = 0 BEGIN INSERT INTO archive_electric_water_meter_month ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, sub_result, avg_rawdata, sum_rawdata, is_complete, repeat_times, fail_reason) VALUES ( @device_number, @point, @start_timestamp, @end_timestamp, @count_rawdata, @min_rawdata, @max_rawdata, @max_rawdata - @min_rawdata, @avg_rawdata, @sum_rawdata, @is_complete, @repeat_times, @fail_reason) END COMMIT TRANSACTION;"; await backgroundServiceRepository.ExecuteSql(sql, electricArchiveMonthRawDatas); if (!string.IsNullOrEmpty(saveToMSDB) && saveToMSDB == "1") { await backgroundServiceMsSqlRepository.ExecuteSql(mySql, electricArchiveMonthRawDatas); } } if (waterArchiveMonthRawDatas.Count() > 0) { var sql = $@" UPDATE archive_electric_water_meter_month SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, sub_result = @max_rawdata - @min_rawdata, avg_rawdata = @avg_rawdata, sum_rawdata = @sum_rawdata, is_complete = @is_complete, repeat_times = @repeat_times, fail_reason = @fail_reason, updated_at = @updated_at WHERE device_number = @device_number AND point = @point AND start_timestamp = @start_timestamp; INSERT INTO archive_electric_water_meter_month ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, sub_result, avg_rawdata, sum_rawdata, is_complete, repeat_times, fail_reason) SELECT @device_number, @point, @start_timestamp, @end_timestamp, @count_rawdata, @min_rawdata, @max_rawdata, @max_rawdata - @min_rawdata, @avg_rawdata, @sum_rawdata, @is_complete, @repeat_times, @fail_reason WHERE ROW_COUNT() = 0;"; var mySql = $@"BEGIN TRANSACTION; UPDATE archive_electric_water_meter_month SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, sub_result = @max_rawdata - @min_rawdata, avg_rawdata = @avg_rawdata, sum_rawdata = @sum_rawdata, is_complete = @is_complete, repeat_times = @repeat_times, fail_reason = @fail_reason, updated_at = @updated_at WHERE device_number = @device_number AND point = @point AND start_timestamp = @start_timestamp; IF @@ROWCOUNT = 0 BEGIN INSERT INTO archive_electric_water_meter_month ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, sub_result, avg_rawdata, sum_rawdata, is_complete, repeat_times, fail_reason) VALUES ( @device_number, @point, @start_timestamp, @end_timestamp, @count_rawdata, @min_rawdata, @max_rawdata, @max_rawdata - @min_rawdata, @avg_rawdata, @sum_rawdata, @is_complete, @repeat_times, @fail_reason) END COMMIT TRANSACTION;"; await backgroundServiceRepository.ExecuteSql(sql, waterArchiveMonthRawDatas); if (!string.IsNullOrEmpty(saveToMSDB) && saveToMSDB == "1") { await backgroundServiceMsSqlRepository.ExecuteSql(mySql, waterArchiveMonthRawDatas); } } await task_Detail.InsertWorkTime_End("ArchiveElectricMeterDayJob", "Month", "任務完成"); } catch (Exception exception) { await task_Detail.WorkFail("ArchiveElectricMeterDayJob", "Month", exception.ToString()); logger.LogError("【ArchiveElectricMeterDayJob】【月歸檔】【任務失敗】"); logger.LogError("【ArchiveElectricMeterDayJob】【月歸檔】【任務失敗】[Exception]:{0}", exception.ToString()); } finally { if (archiveResponse != null) { archiveResponse.Dispose(); archiveResponse.Close(); } } } #endregion 月歸檔 #region 補償機制 ////取得連線字串 //if (await task_Detail.GetNeedWorkTask("ArchiveElectricMeterDayJob", "Compensate")) //{ // try // { // await task_Detail.InsertWorkTime("ArchiveElectricMeterDayJob", "Compensate", "補償機制任務開始"); // ProcEletricMeterService procEletricMeterService = new ProcEletricMeterService(backgroundServiceRepository, backgroundServiceMsSqlRepository); // await procEletricMeterService.ArchiveData(); // await task_Detail.InsertWorkTime_End("ArchiveElectricMeterDayJob", "Compensate", "任務完成"); // } // catch (Exception ex) // { // await task_Detail.WorkFail("ArchiveElectricMeterDayJob", "Compensate", ex.ToString()); // } //} #endregion 補償機制 await task_Detail.InsertWorkTime_End("ArchiveElectricMeterDayJob", "All", "任務完成"); } } catch (Exception exception) { await task_Detail.WorkFail("ArchiveElectricMeterDayJob", "All", exception.ToString()); logger.LogError("【ArchiveElectricMeterDayJob】【任務失敗】"); logger.LogError("【ArchiveElectricMeterDayJob】【任務失敗】[Exception]:{0}, {1}", exception.ToString(), "device_number = " + device_number); } } public IEnumerable EachDay(string from, string thru) { var strtday = DateTime.Parse(from).AddDays(-1); //每次重做 2天 var endday = DateTime.Parse(thru); for (var day = strtday.Date; day.Date <= endday.Date; day = day.AddDays(1)) yield return day; } private List> ArrangeRawData(DeviceNumberPoint deviceNumberPoint, JObject jsonResult) { List> arrangeRawDatas = new List>(); try { var histories = jsonResult["obj"]["list"]; var rawdateCount = Convert.ToInt32(jsonResult["obj"]["int"]["@val"].ToString()); if (rawdateCount == 0) { return null; } if (histories != null && histories.HasValues) { if (rawdateCount > 1) { //多筆資料 foreach (var history in histories) { Dictionary arrangeRawData = new Dictionary(); arrangeRawData.Add("@device_number", deviceNumberPoint.DeviceNumber); arrangeRawData.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"); arrangeRawData.Add("@start_timestamp", startTimstamp); break; case "end": var endTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss"); arrangeRawData.Add("@end_timestamp", endTimstamp); break; } } } //區間內資料筆數 if (history["int"] != null && history["int"].HasValues) { var count = Convert.ToInt32(histories["obj"]["int"]["@val"].ToString()); arrangeRawData.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()); arrangeRawData.Add("@min_rawdata", min); break; case "max": var max = Convert.ToDecimal(real["@val"].ToString()); arrangeRawData.Add("@max_rawdata", max); break; case "avg": var avg = Convert.ToDecimal(real["@val"].ToString()); arrangeRawData.Add("@avg_rawdata", avg); break; case "sum": var sum = Decimal.Parse(real["@val"].ToString(), System.Globalization.NumberStyles.Float); arrangeRawData.Add("@sum_rawdata", sum); break; } } } arrangeRawData.Add("@is_complete", 1); arrangeRawData.Add("@repeat_times", 0); arrangeRawData.Add("@fail_reason", null); arrangeRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); arrangeRawDatas.Add(arrangeRawData); } } else { //單筆資料 Dictionary arrangeRawData = new Dictionary(); arrangeRawData.Add("@device_number", deviceNumberPoint.DeviceNumber); arrangeRawData.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"); arrangeRawData.Add("@start_timestamp", startTimstamp); break; case "end": var endTimstamp = Convert.ToDateTime(abstime["@val"].ToString()).ToString("yyyy-MM-dd HH:mm:ss"); arrangeRawData.Add("@end_timestamp", endTimstamp); break; } } } //區間內資料筆數 if (histories["obj"]["int"] != null && histories["obj"]["int"].HasValues) { var count = Convert.ToInt32(histories["obj"]["int"]["@val"].ToString()); arrangeRawData.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()); arrangeRawData.Add("@min_rawdata", min); break; case "max": var max = Convert.ToDecimal(real["@val"].ToString()); arrangeRawData.Add("@max_rawdata", max); break; case "avg": var avg = Convert.ToDecimal(real["@val"].ToString()); arrangeRawData.Add("@avg_rawdata", avg); break; case "sum": var sum = Decimal.Parse(real["@val"].ToString(), System.Globalization.NumberStyles.Float); arrangeRawData.Add("@sum_rawdata", sum); break; } } } arrangeRawData.Add("@is_complete", 1); arrangeRawData.Add("@repeat_times", 0); arrangeRawData.Add("@fail_reason", null); arrangeRawData.Add("@updated_at", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); arrangeRawDatas.Add(arrangeRawData); } } return arrangeRawDatas; } catch (Exception ex) { return arrangeRawDatas; } } } }