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 = "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); 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); 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 = $@" "; //Stopwatch stopWatch = new Stopwatch(); //stopWatch.Start(); //抓取每個設備的資料 List> electericArchiveDayRawDatas = new List>(); List> waterArchiveDayRawDatas = 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 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", startTimestamp.Replace("T", " ").Substring(0, 19)); archiveDayRawData.Add("@end_timestamp", endTimestamp.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) { 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", startTimestamp.Replace("T", " ").Substring(0, 19)); archiveDayRawData.Add("@end_timestamp", endTimestamp.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_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, `kwh_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_meter_day_{dbDateName} SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, kwh_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_meter_day_{dbDateName} ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, kwh_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; IF OBJECT_ID(N'dbo.archive_electric_meter_day_{dbDateName}', N'U') is null BEGIN CREATE TABLE [dbo].[archive_electric_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, [kwh_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_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_meter_day_{dbDateName}] ADD CONSTRAINT [DF_archive_electric_meter_day_{dbDateName}_repeat_times] DEFAULT ((0)) FOR [repeat_times] ALTER TABLE [dbo].[archive_electric_meter_day_{dbDateName}] ADD CONSTRAINT [DF_archive_electric_meter_day_{dbDateName}_created_at] DEFAULT (getdate()) FOR [created_at] ALTER TABLE [dbo].[archive_electric_meter_day_{dbDateName}] ADD CONSTRAINT [DF_archive_electric_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_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_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_meter_day_{dbDateName}', @level2type=N'COLUMN',@level2name=N'fail_reason' END UPDATE archive_electric_meter_day_{dbDateName} SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, kwh_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_meter_day_{dbDateName} ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, kwh_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_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, `kwh_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_water_meter_day_{dbDateName} SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, kwh_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_water_meter_day_{dbDateName} ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, kwh_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; IF OBJECT_ID(N'dbo.archive_water_meter_day_{dbDateName}', N'U') is null BEGIN CREATE TABLE [dbo].[archive_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, [kwh_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_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_water_meter_day_{dbDateName}] ADD CONSTRAINT [DF_archive_water_meter_day_{dbDateName}_repeat_times] DEFAULT ((0)) FOR [repeat_times] ALTER TABLE [dbo].[archive_water_meter_day_{dbDateName}] ADD CONSTRAINT [DF_archive_water_meter_day_{dbDateName}_created_at] DEFAULT (getdate()) FOR [created_at] ALTER TABLE [dbo].[archive_water_meter_day_{dbDateName}] ADD CONSTRAINT [DF_archive_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_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_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_water_meter_day_{dbDateName}', @level2type=N'COLUMN',@level2name=N'fail_reason' END UPDATE archive_water_meter_day_{dbDateName} SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, kwh_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_water_meter_day_{dbDateName} ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, kwh_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_meter_week SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, kwh_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_meter_week ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, kwh_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_meter_week SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, kwh_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_meter_week ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, kwh_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_water_meter_week SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, kwh_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_water_meter_week ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, kwh_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_water_meter_week SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, kwh_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_water_meter_week ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, kwh_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 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 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_meter_month SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, kwh_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_meter_month ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, kwh_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_meter_month SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, kwh_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_meter_month ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, kwh_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_water_meter_month SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, kwh_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_water_meter_month ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, kwh_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_water_meter_month SET count_rawdata = @count_rawdata, min_rawdata = @min_rawdata, max_rawdata = @max_rawdata, kwh_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_water_meter_month ( device_number, point, start_timestamp, end_timestamp, count_rawdata, min_rawdata, max_rawdata, kwh_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); } } 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; } } } }