336 lines
21 KiB
C#
336 lines
21 KiB
C#
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
|
||
{
|
||
/// <summary>
|
||
/// 電錶歸檔,每小時執行,只執行小時歸檔
|
||
/// </summary>
|
||
[DisallowConcurrentExecution]
|
||
class ArchiveElectricMeterHourJob : IJob
|
||
{
|
||
private readonly ILogger<ArchiveElectricMeterHourJob> logger;
|
||
private readonly IBackgroundServiceRepository backgroundServiceRepository;
|
||
private readonly ILogger<Task_Detail> loggers;
|
||
|
||
public ArchiveElectricMeterHourJob(
|
||
ILogger<ArchiveElectricMeterHourJob> logger,
|
||
IBackgroundServiceRepository backgroundServiceRepository, ILogger<Task_Detail> 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<KeyValue>(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>("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>("device_item", sPointWhere, new { sub_system_guid = electricMeterGuid });
|
||
#endregion 找出所有電錶系統的點位
|
||
|
||
#region 組合出所有電錶設備點位
|
||
List<DeviceNumberPoint> deviceNumberPoints = new List<DeviceNumberPoint>();
|
||
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<KeyValue>(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 = $@"<obj is='obix: HistoryFilter'>
|
||
<abstime name='start' val='{startTimestamp}' />
|
||
<abstime name='end' val='{endTimestamp}' />
|
||
<reltime name='interval' val = 'PT1H' />
|
||
</obj>";
|
||
|
||
//Stopwatch stopWatch = new Stopwatch();
|
||
//stopWatch.Start();
|
||
|
||
//抓取每個設備的資料
|
||
List<Dictionary<string, object>> archiveHourRawDatas = new List<Dictionary<string, object>>();
|
||
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<string, object> archiveHourRawData = new Dictionary<string, object>();
|
||
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<string, object> archiveHourRawData = new Dictionary<string, object>();
|
||
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<string, object> archiveHourRawData = new Dictionary<string, object>();
|
||
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());
|
||
}
|
||
}
|
||
}
|
||
}
|