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