123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556 |
- using System;
- using System.Collections.Generic;
- using System.IdentityModel.Tokens.Jwt;
- using System.Linq;
- using System.Security.Claims;
- using System.Text;
- using FMSAdmin.Data;
- using FMSAdmin.Helpers;
- using FMSAdmin.Entities;
- using Microsoft.EntityFrameworkCore;
- using Microsoft.Extensions.Logging;
- using Microsoft.Extensions.Options;
- using Microsoft.IdentityModel.Tokens;
- using FMSAdmin.Models;
- using System.ComponentModel.DataAnnotations;
- using System.Threading.Tasks;
- using System.Net.Http;
- using System.Xml.Linq;
- using System.Net;
- using System.Data;
- using System.IO;
- namespace FMSAdmin.Services {
- public class SiteWeatherInfoService {
- private readonly ILogger<SiteWeatherInfoService> _logger;
- private readonly AppSettings _appSettings;
- private readonly FMSContext _context;
- public SiteWeatherInfoService(
- ILogger<SiteWeatherInfoService> logger,
- IOptions<AppSettings> appSettings,
- FMSContext context,
- StorageHelper storage
- ) {
- _logger = logger;
- _appSettings = appSettings.Value;
- _context = context;
- }
- public DataTable WeatherStat(int dayAgo = 0) {
- var query = $@"
- SELECT Sido AS [시도], Sigun AS [구군], [00],[01],[02],[03],[04],[05],[06],[07],[08],[09],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[21],[22],[23] FROM
- (
- SELECT weather.Sido, weather.Sigun, weather.CurrentTemp, DATEPART(HOUR, BaseTime) as Hour FROM SiteWeatherInfo weather
- LEFT JOIN CmSite site ON site.apiSido = weather.Sido AND site.ApiSigun = weather.Sigun
- WHERE CAST(weather.BaseTime AS DATE) = CAST(DATEADD(DAY, {dayAgo}, GETDATE()) AS DATE)
- ) T
- PIVOT (
- MAX(CurrentTemp) FOR Hour in ([00],[01],[02],[03],[04],[05],[06],[07],[08],[09],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[21],[22],[23])
- ) AS PV
- ";
- var conn = _context.Database.GetDbConnection();
- conn.Open();
- var command = conn.CreateCommand();
- command.CommandText = query;
- var reader = command.ExecuteReader();
- DataTable dt = new DataTable();
- dt.Load(reader);
- return dt;
- }
- public string ReplaceSido(string sido) {
- string result = sido.ToString();
- result = result.Replace("특별시", "시");
- result = result.Replace("광역시", "시");
- result = result.Replace("특별자치도", "도");
- result = result.Replace("특별자치시", "시");
- return result;
- }
- public SiteWeatherInfo GetInfo(int siteId, string sido = null, string sigun = null, bool weather = true, bool dust = true) {
- SiteWeatherInfo weatherInfo = null;
- var site = _context.CmSite.Where(x => x.SiteId == siteId).FirstOrDefault();
- if (site != null) {
- if (string.IsNullOrEmpty(sido)) {
- sido = site.ApiSido;
- }
- if (string.IsNullOrEmpty(sigun)) {
- sigun = site.ApiSigun;
- }
- }
- if (string.IsNullOrEmpty(sido)) {
- sido = "서울시";
- }
- if (string.IsNullOrEmpty(sigun)) {
- sigun = "용산구";
- }
- sido = this.ReplaceSido(sido);
- var basetime = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, 0, 0);
- var query = from x in _context.SiteWeatherInfo
- where x.Sido == sido && x.Sigun == sigun && x.BaseTime == basetime
- orderby x.BaseTime descending
- select x;
- if (query.Count() > 0) {
- weatherInfo = query.FirstOrDefault();
- if (weatherInfo.CurrentTemp != null && weatherInfo.Pm10 != null) {
- return weatherInfo;
- }
- }
- var isNew = false;
- if (weatherInfo == null) {
- weatherInfo = new SiteWeatherInfo {
- Sido = sido,
- Sigun = sigun,
- BaseTime = basetime,
- };
- isNew = true;
- }
- try {
- if (weatherInfo.CurrentTemp == null && weather) {
- var shortTermNow = _apiShortTermNow(sido, sigun);
- weatherInfo.ShortTermNowTime = shortTermNow.BaseTime;
- if (shortTermNow.T1H != null) {
- weatherInfo.CurrentTemp = Util.ToDouble(shortTermNow.T1H);
- }
- if (shortTermNow.RN1 != null) {
- weatherInfo.Sky = Util.ToInt(shortTermNow.RN1);
- }
- if (shortTermNow.REH != null) {
- weatherInfo.Humidity = Util.ToDouble(shortTermNow.REH);
- }
- if (shortTermNow.PTY != null) {
- weatherInfo.RainType = Util.ToInt(shortTermNow.PTY);
- }
- if (shortTermNow.RN1 != null) {
- weatherInfo.Rain = Util.ToDouble(shortTermNow.RN1);
- }
- if (shortTermNow.LGT != null) {
- weatherInfo.Thunder = Util.ToInt(shortTermNow.LGT);
- }
- if (shortTermNow.VEC != null) {
- weatherInfo.WindAngle = Util.ToInt(shortTermNow.VEC);
- }
- if (shortTermNow.WSD != null) {
- weatherInfo.WindSpeed = Util.ToDouble(shortTermNow.WSD);
- }
- }
- if (weatherInfo.HighTemp == null && weather) {
- var forecast = _apiForecast(sido, sigun);
- weatherInfo.ForecastTime = forecast.BaseTime;
- if (forecast.TMX != null) {
- weatherInfo.HighTemp = Util.ToDouble(forecast.TMX);
- }
- if (forecast.TMN != null) {
- weatherInfo.LowTemp = Util.ToDouble(forecast.TMN);
- }
- }
- } catch (ApiException ex) {
- _logger.LogWarning(ex.Message);
- } catch (Exception ex) {
- _logger.LogError(ex, "");
- }
- try {
- if (weatherInfo.Pm10 == null && dust) {
- var dustHourly = _apiDustHourly(sido, sigun);
- if (dustHourly != null) {
- if (dustHourly.DataTime != null) {
- weatherInfo.DustTime = _parseDate(dustHourly.DataTime);
- }
- if (dustHourly.Pm10Value != null) {
- weatherInfo.Pm10 = Util.ToDouble(dustHourly.Pm10Value);
- }
- if (dustHourly.Pm25Value != null) {
- weatherInfo.Pm25 = Util.ToDouble(dustHourly.Pm25Value);
- }
- }
- }
- if (weatherInfo.CurrentTemp < -200 || weatherInfo.CurrentTemp > 200) {
- weatherInfo.CurrentTemp = null;
- //throw new Exception("잘못된 데이터");
- }
- weatherInfo.IsNew = true;
- if (isNew) {
- _context.SiteWeatherInfo.Add(weatherInfo);
- }
- _context.SaveChanges();
- } catch (ApiException ex) {
- _logger.LogWarning(ex.Message);
- } catch (Exception ex) {
- _logger.LogError(ex, "");
- }
- if (weatherInfo.CurrentTemp == null && weatherInfo.Pm10 == null) {
- var query2 = from x in _context.SiteWeatherInfo
- where x.Sido == sido && x.Sigun == sigun && x.BaseTime <= basetime
- orderby x.BaseTime descending
- select x;
- if (query2.Count() > 0) {
- weatherInfo = query.FirstOrDefault();
- return weatherInfo;
- }
- }
- return weatherInfo;
- }
- private DateTime? _parseDate(string datestr) {
- var items = datestr.Split(" ");
- DateTime? date = null;
- try {
- if (items.Length >= 2 && items[1].StartsWith("24")) {
- date = DateTime.Parse(items[0]);
- date.Value.AddDays(1);
- } else {
- date = DateTime.Parse(datestr);
- }
- } catch (Exception ex) {
- _logger.LogError(ex, "");
- }
- return date;
- }
- private DustApiItem _apiDustHourly(string sido, string sigun) {
- if (sido == null) sido = "";
- if (sido == "경상북도") {
- sido = "경북";
- } else if (sido == "경상남도") {
- sido = "경남";
- } else if (sido == "전라북도") {
- sido = "전북";
- } else if (sido == "전라남도") {
- sido = "전남";
- } else if (sido == "충청북도") {
- sido = "충북";
- } else if (sido == "충청남도") {
- sido = "충남";
- }
- if (sido[sido.Length - 1] == '시') {
- sido = sido.Substring(0, sido.Length - 1);
- }
- if (sido[sido.Length - 1] == '도') {
- sido = sido.Substring(0, sido.Length - 1);
- }
- var sidoName = WebUtility.UrlDecode(sido);
- //var forecast = $"http://openapi.airkorea.or.kr/openapi/services/rest/ArpltnInforInqireSvc/getCtprvnMesureSidoLIst?serviceKey={_appSettings.DustApiKey}&numOfRows=100&pageNo=1&sidoName={sidoName}&searchCondition=HOUR";
- var forecast = $"http://apis.data.go.kr/B552584/ArpltnStatsSvc/getCtprvnMesureSidoLIst?serviceKey={_appSettings.DustApiKey}&numOfRows=100&pageNo=1&sidoName={sidoName}&searchCondition=HOUR";
- string content = null;
- content = pullUrl(forecast);
- // _logger.LogInformation(content);
- XElement xml = XElement.Parse(content);
- var resultCode = xml.Descendants("resultCode").FirstOrDefault()?.Value;
- var resultMsg = xml.Descendants("resultMsg").FirstOrDefault()?.Value;
- if (resultCode != "00") {
- throw new ApiException($"apiDustHourly {resultCode}:{resultMsg}");
- }
- var items = from item in xml.Descendants("item")
- select new DustApiItem {
- DataTime = item.Element("dataTime")?.Value,
- CityName = item.Element("cityName")?.Value,
- So2Value = item.Element("so2Value")?.Value,
- CoValue = item.Element("coValue")?.Value,
- No2Value = item.Element("no2Value")?.Value,
- Pm10Value = item.Element("pm10Value")?.Value,
- Pm25Value = item.Element("pm25Value")?.Value,
- };
- var result = items.Where(x => x.CityName == sigun).FirstOrDefault();
- if (result == null) {
- result = items.FirstOrDefault();
- }
- return result;
- }
- private WeatherForecast _apiForecast(string sido, string sigun, string gu = null) {
- var pos = _GetRegionPosition(sido, sigun, gu);
- var nx = pos.Nx;
- var ny = pos.Ny;
- var forenow = DateTime.Now.AddHours(-4);
- var forehour = forenow.Hour;
- if (forehour >= 2 && forehour < 5) {
- forehour = 2;
- }
- if (forehour < 2) {
- forenow = forenow.AddDays(-1);
- forehour = 23;
- } else {
- // 2시부터 23시까지 3시간 간격으로 발표
- forehour = (int)Math.Floor((float)(forehour - 2) / 3) * 3 + 2;
- }
- forenow = new DateTime(forenow.Year, forenow.Month, forenow.Day, forehour, 0, 0);
- var targetnow = forenow.AddHours(4);
- var foredate = forenow.ToString("yyyyMMdd");
- var foretime = forenow.ToString("HH00");
- var targettime = targetnow.ToString("HH00");
- //_logger.LogInformation("foredate:" + foredate);
- //_logger.LogInformation("foretime:" + foretime);
- //_logger.LogInformation("targettime:" + targettime);
- var forecast = $"http://apis.data.go.kr/1360000/VilageFcstInfoService/getVilageFcst?serviceKey={_appSettings.WeatherApiKey}&pageNo=1&numOfRows=100&dataType=XML&base_date={foredate}&base_time={foretime}&nx={nx}&ny={ny}";
- //_logger.LogInformation(forecast);
- string content = null;
- content = pullUrl(forecast);
- //_logger.LogInformation(content);
- XElement xml = XElement.Parse(content);
- var resultCode = xml.Descendants("resultCode").FirstOrDefault()?.Value;
- var resultMsg = xml.Descendants("resultMsg").FirstOrDefault()?.Value;
- if (resultCode != "00") {
- throw new ApiException($"apiForecast {resultCode}:{resultMsg}");
- }
- var items = from item in xml.Descendants("item")
- select new WeatherApiItem {
- BaseDate = item.Element("baseDate")?.Value,
- BaseTime = item.Element("baseTime")?.Value,
- Category = item.Element("category")?.Value,
- FcstValue = item.Element("fcstValue")?.Value,
- FcstTime = item.Element("fcstTime")?.Value,
- };
- var list = items.ToList();
- //_logger.LogInformation(list.Dump());
- var result = new WeatherForecast();
- result.BaseTime = targetnow;
- result.ForecastTime = forenow;
- result.POP = list.Where(x => x.Category == "POP").Select(x => x.FcstValue).FirstOrDefault();
- result.PTY = list.Where(x => x.Category == "PTY").Select(x => x.FcstValue).FirstOrDefault();
- result.R06 = list.Where(x => x.Category == "R06").Select(x => x.FcstValue).FirstOrDefault();
- result.REH = list.Where(x => x.Category == "REH").Select(x => x.FcstValue).FirstOrDefault();
- result.S06 = list.Where(x => x.Category == "S06").Select(x => x.FcstValue).FirstOrDefault();
- result.SKY = list.Where(x => x.Category == "SKY").Select(x => x.FcstValue).FirstOrDefault();
- result.T3H = list.Where(x => x.Category == "T3H").Select(x => x.FcstValue).FirstOrDefault();
- result.TMN = list.Where(x => x.Category == "TMN").Select(x => x.FcstValue).FirstOrDefault();
- result.TMX = list.Where(x => x.Category == "TMX").Select(x => x.FcstValue).FirstOrDefault();
- result.UUU = list.Where(x => x.Category == "UUU").Select(x => x.FcstValue).FirstOrDefault();
- result.VVV = list.Where(x => x.Category == "VVV").Select(x => x.FcstValue).FirstOrDefault();
- result.VEC = list.Where(x => x.Category == "VEC").Select(x => x.FcstValue).FirstOrDefault();
- result.WSD = list.Where(x => x.Category == "WSD").Select(x => x.FcstValue).FirstOrDefault();
- return result;
- }
- private WeatherShortTermNow _apiShortTermNow(string sido, string sigun, string gu = null) {
- var pos = _GetRegionPosition(sido, sigun, gu);
- var nx = pos.Nx;
- var ny = pos.Ny;
- var nowminute = DateTime.Now.Minute;
- var shortnow = DateTime.Now;
- if (nowminute <= 40) {
- shortnow = shortnow.AddHours(-1);
- }
- shortnow = new DateTime(shortnow.Year, shortnow.Month, shortnow.Day, shortnow.Hour, 0, 0);
- var nowdate = shortnow.ToString("yyyyMMdd");
- var nowtime = shortnow.ToString("HH00");
- var shortNow = $"http://apis.data.go.kr/1360000/VilageFcstInfoService/getUltraSrtNcst?serviceKey={_appSettings.WeatherApiKey}&pageNo=1&numOfRows=100&dataType=XML&base_date={nowdate}&base_time={nowtime}&nx={nx}&ny={ny}";
- //_logger.LogInformation(shortNow);
- string content = null;
- content = pullUrl(shortNow);
- //_logger.LogInformation(content);
- XElement xml = XElement.Parse(content);
- var resultCode = xml.Descendants("resultCode").FirstOrDefault()?.Value;
- var resultMsg = xml.Descendants("resultMsg").FirstOrDefault()?.Value;
- if (resultCode != "00") {
- throw new ApiException($"apiShortTermNow {resultCode}:{resultMsg}");
- }
- var items = from item in xml.Descendants("item")
- select new WeatherApiItem {
- BaseDate = item.Element("baseDate")?.Value,
- BaseTime = item.Element("baseTime")?.Value,
- Category = item.Element("category")?.Value,
- ObsrValue = item.Element("obsrValue")?.Value,
- };
- var list = items.ToList();
- //_logger.LogInformation(list.Dump());
- var result = new WeatherShortTermNow();
- result.BaseTime = shortnow;
- result.T1H = list.Where(x => x.Category == "T1H").Select(x => x.ObsrValue).FirstOrDefault();
- result.RN1 = list.Where(x => x.Category == "RN1").Select(x => x.ObsrValue).FirstOrDefault();
- result.SKY = list.Where(x => x.Category == "SKY").Select(x => x.ObsrValue).FirstOrDefault();
- result.UUU = list.Where(x => x.Category == "UUU").Select(x => x.ObsrValue).FirstOrDefault();
- result.VVV = list.Where(x => x.Category == "VVV").Select(x => x.ObsrValue).FirstOrDefault();
- result.REH = list.Where(x => x.Category == "REH").Select(x => x.ObsrValue).FirstOrDefault();
- result.PTY = list.Where(x => x.Category == "PTY").Select(x => x.ObsrValue).FirstOrDefault();
- result.LGT = list.Where(x => x.Category == "LGT").Select(x => x.ObsrValue).FirstOrDefault();
- result.VEC = list.Where(x => x.Category == "VEC").Select(x => x.ObsrValue).FirstOrDefault();
- result.WSD = list.Where(x => x.Category == "WSD").Select(x => x.ObsrValue).FirstOrDefault();
- return result;
- }
- private WeatherRegionNxNy _GetRegionPosition(string sido, string sigun, string gu = null) {
- sido = sido.Trim();
- if (sido == "서울시") {
- sido = "서울특별시";
- } else if (sido == "제주도") {
- sido = "제주특별자치도";
- } else if (sido == "인천시") {
- sido = "인천광역시";
- } else if (sido == "광주시") {
- sido = "광주광역시";
- } else if (sido == "대구시") {
- sido = "대구광역시";
- } else if (sido == "대전시") {
- sido = "대전광역시";
- } else if (sido == "부산시") {
- sido = "부산광역시";
- } else if (sido == "울산시") {
- sido = "울산광역시";
- } else if (sido == "세종시") {
- sido = "세종특별자치시";
- }
- var query = _context.WeatherRegionNxNy.Where(x => x.Sido == sido && x.Sigun == sigun);
- WeatherRegionNxNy find = null;
- if (!string.IsNullOrEmpty(gu)) {
- if (query.Where(x => x.Gu == gu).Count() > 0) {
- find = query.Where(x => x.Gu == gu).FirstOrDefault();
- } else {
- find = query.FirstOrDefault();
- }
- } else {
- find = query.FirstOrDefault();
- }
- return find;
- }
- private string pullUrl(string url) {
- // Create a request for the URL.
- HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
- request.Timeout = 5000;
- // If required by the server, set the credentials.
- request.Credentials = CredentialCache.DefaultCredentials;
- // Get the response.
- HttpWebResponse response = (HttpWebResponse)request.GetResponse();
- // Display the status.
- // Get the stream containing content returned by the server.
- Stream dataStream = response.GetResponseStream();
- // Open the stream using a StreamReader for easy access.
- StreamReader reader = new StreamReader(dataStream);
- // Read the content.
- string responseFromServer = reader.ReadToEnd();
- // Display the content.
- reader.Close();
- dataStream.Close();
- response.Close();
- return responseFromServer;
- }
- }
- public class DustApiItem {
- public string DataTime { get; set; }
- public string CityName { get; set; }
- public string So2Value { get; set; }
- public string CoValue { get; set; }
- public string O3Value { get; set; }
- public string No2Value { get; set; }
- public string Pm10Value { get; set; }
- public string Pm25Value { get; set; }
- }
- public class WeatherApiItem {
- public string BaseDate { get; set; }
- public string BaseTime { get; set; }
- public string Category { get; set; }
- public string ObsrValue { get; set; }
- public string FcstValue { get; set; }
- public string FcstTime { get; set; }
- }
- public class WeatherForecast {
- public WeatherForecast() {
- }
- public DateTime BaseTime;
- public DateTime ForecastTime;
- [Display(Name = "강수확률")]
- public string POP { get; set; }
- [Display(Name = "강수형태")]
- public string PTY { get; set; }
- [Display(Name = "6시간 강수량")]
- public string R06 { get; set; }
- [Display(Name = "습도")]
- public string REH { get; set; }
- [Display(Name = "6시간 신적설")]
- public string S06 { get; set; }
- [Display(Name = "하늘상태")]
- public string SKY { get; set; }
- [Display(Name = "3시간 기온")]
- public string T3H { get; set; }
- [Display(Name = "아침 최저기온")]
- public string TMN { get; set; }
- [Display(Name = "낮 최고기온")]
- public string TMX { get; set; }
- [Display(Name = "풍속(동서)")]
- public string UUU { get; set; }
- [Display(Name = "풍속(남북)")]
- public string VVV { get; set; }
- [Display(Name = "풍향")]
- public string VEC { get; set; }
- [Display(Name = "풍속")]
- public string WSD { get; set; }
- }
- public class WeatherShortTermNow {
- public WeatherShortTermNow() {
- }
- public DateTime BaseTime;
- [Display(Name = "기온")]
- public string T1H { get; set; }
- [Display(Name = "1시간 강수량")]
- public string RN1 { get; set; }
- [Display(Name = "하늘상태")]
- public string SKY { get; set; }
- [Display(Name = "동서바람성분")]
- public string UUU { get; set; }
- [Display(Name = "남북바람성분")]
- public string VVV { get; set; }
- [Display(Name = "습도")]
- public string REH { get; set; }
- [Display(Name = "강수형태")]
- public string PTY { get; set; }
- [Display(Name = "낙뢰")]
- public string LGT { get; set; }
- [Display(Name = "풍향")]
- public string VEC { get; set; }
- [Display(Name = "풍속")]
- public string WSD { get; set; }
- }
- }
|