WeatherProvider.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. using System.Globalization;
  2. using MediaBrowser.Common.Net;
  3. using MediaBrowser.Controller.Weather;
  4. using MediaBrowser.Model.Logging;
  5. using MediaBrowser.Model.Serialization;
  6. using MediaBrowser.Model.Weather;
  7. using System;
  8. using System.Linq;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. namespace MediaBrowser.Server.Implementations.WorldWeatherOnline
  12. {
  13. /// <summary>
  14. /// Based on http://www.worldweatheronline.com/free-weather-feed.aspx
  15. /// The classes in this file are a reproduction of the json output, which will then be converted to our weather model classes
  16. /// </summary>
  17. public class WeatherProvider : IWeatherProvider
  18. {
  19. /// <summary>
  20. /// Gets or sets the logger.
  21. /// </summary>
  22. /// <value>The logger.</value>
  23. private ILogger Logger { get; set; }
  24. /// <summary>
  25. /// Gets the json serializer.
  26. /// </summary>
  27. /// <value>The json serializer.</value>
  28. protected IJsonSerializer JsonSerializer { get; private set; }
  29. /// <summary>
  30. /// The _HTTP client
  31. /// </summary>
  32. private IHttpClient HttpClient { get; set; }
  33. /// <summary>
  34. /// Initializes a new instance of the <see cref="WeatherProvider" /> class.
  35. /// </summary>
  36. /// <param name="jsonSerializer">The json serializer.</param>
  37. /// <param name="httpClient">The HTTP client.</param>
  38. /// <param name="logger">The logger.</param>
  39. /// <exception cref="System.ArgumentNullException">logger</exception>
  40. public WeatherProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogger logger)
  41. {
  42. if (logger == null)
  43. {
  44. throw new ArgumentNullException("logger");
  45. }
  46. if (httpClient == null)
  47. {
  48. throw new ArgumentNullException("httpClient");
  49. }
  50. if (jsonSerializer == null)
  51. {
  52. throw new ArgumentNullException("jsonSerializer");
  53. }
  54. JsonSerializer = jsonSerializer;
  55. HttpClient = httpClient;
  56. Logger = logger;
  57. }
  58. /// <summary>
  59. /// The _weather semaphore
  60. /// </summary>
  61. private readonly SemaphoreSlim _weatherSemaphore = new SemaphoreSlim(10, 10);
  62. /// <summary>
  63. /// Gets the weather info async.
  64. /// </summary>
  65. /// <param name="location">The location.</param>
  66. /// <param name="cancellationToken">The cancellation token.</param>
  67. /// <returns>Task{WeatherInfo}.</returns>
  68. /// <exception cref="System.ArgumentNullException">location</exception>
  69. public async Task<WeatherInfo> GetWeatherInfoAsync(string location, CancellationToken cancellationToken)
  70. {
  71. if (string.IsNullOrWhiteSpace(location))
  72. {
  73. throw new ArgumentNullException("location");
  74. }
  75. if (cancellationToken == null)
  76. {
  77. throw new ArgumentNullException("cancellationToken");
  78. }
  79. const int numDays = 5;
  80. const string apiKey = "24902f60f1231941120109";
  81. var url = "http://free.worldweatheronline.com/feed/weather.ashx?q=" + location + "&format=json&num_of_days=" + numDays + "&key=" + apiKey;
  82. Logger.Info("Accessing weather from " + url);
  83. using (var stream = await HttpClient.Get(url, _weatherSemaphore, cancellationToken).ConfigureAwait(false))
  84. {
  85. var data = JsonSerializer.DeserializeFromStream<WeatherResult>(stream).data;
  86. return GetWeatherInfo(data);
  87. }
  88. }
  89. /// <summary>
  90. /// Converst the json output to our WeatherInfo model class
  91. /// </summary>
  92. /// <param name="data">The data.</param>
  93. /// <returns>WeatherInfo.</returns>
  94. private WeatherInfo GetWeatherInfo(WeatherData data)
  95. {
  96. var info = new WeatherInfo();
  97. if (data.current_condition != null)
  98. {
  99. var condition = data.current_condition.FirstOrDefault();
  100. if (condition != null)
  101. {
  102. info.CurrentWeather = condition.ToWeatherStatus();
  103. }
  104. }
  105. if (data.weather != null)
  106. {
  107. info.Forecasts = data.weather.Select(w => w.ToWeatherForecast()).ToArray();
  108. }
  109. return info;
  110. }
  111. }
  112. /// <summary>
  113. /// Class WeatherResult
  114. /// </summary>
  115. class WeatherResult
  116. {
  117. /// <summary>
  118. /// Gets or sets the data.
  119. /// </summary>
  120. /// <value>The data.</value>
  121. public WeatherData data { get; set; }
  122. }
  123. /// <summary>
  124. /// Class WeatherData
  125. /// </summary>
  126. public class WeatherData
  127. {
  128. /// <summary>
  129. /// Gets or sets the current_condition.
  130. /// </summary>
  131. /// <value>The current_condition.</value>
  132. public WeatherCondition[] current_condition { get; set; }
  133. /// <summary>
  134. /// Gets or sets the weather.
  135. /// </summary>
  136. /// <value>The weather.</value>
  137. public DailyWeatherInfo[] weather { get; set; }
  138. }
  139. /// <summary>
  140. /// Class WeatherCondition
  141. /// </summary>
  142. public class WeatherCondition
  143. {
  144. /// <summary>
  145. /// Gets or sets the temp_ C.
  146. /// </summary>
  147. /// <value>The temp_ C.</value>
  148. public string temp_C { get; set; }
  149. /// <summary>
  150. /// Gets or sets the temp_ F.
  151. /// </summary>
  152. /// <value>The temp_ F.</value>
  153. public string temp_F { get; set; }
  154. /// <summary>
  155. /// Gets or sets the humidity.
  156. /// </summary>
  157. /// <value>The humidity.</value>
  158. public string humidity { get; set; }
  159. /// <summary>
  160. /// Gets or sets the weather code.
  161. /// </summary>
  162. /// <value>The weather code.</value>
  163. public string weatherCode { get; set; }
  164. protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
  165. /// <summary>
  166. /// To the weather status.
  167. /// </summary>
  168. /// <returns>WeatherStatus.</returns>
  169. public WeatherStatus ToWeatherStatus()
  170. {
  171. return new WeatherStatus
  172. {
  173. TemperatureCelsius = int.Parse(temp_C, UsCulture),
  174. TemperatureFahrenheit = int.Parse(temp_F, UsCulture),
  175. Humidity = int.Parse(humidity, UsCulture),
  176. Condition = DailyWeatherInfo.GetCondition(weatherCode)
  177. };
  178. }
  179. }
  180. /// <summary>
  181. /// Class DailyWeatherInfo
  182. /// </summary>
  183. public class DailyWeatherInfo
  184. {
  185. /// <summary>
  186. /// Gets or sets the date.
  187. /// </summary>
  188. /// <value>The date.</value>
  189. public string date { get; set; }
  190. /// <summary>
  191. /// Gets or sets the precip MM.
  192. /// </summary>
  193. /// <value>The precip MM.</value>
  194. public string precipMM { get; set; }
  195. /// <summary>
  196. /// Gets or sets the temp max C.
  197. /// </summary>
  198. /// <value>The temp max C.</value>
  199. public string tempMaxC { get; set; }
  200. /// <summary>
  201. /// Gets or sets the temp max F.
  202. /// </summary>
  203. /// <value>The temp max F.</value>
  204. public string tempMaxF { get; set; }
  205. /// <summary>
  206. /// Gets or sets the temp min C.
  207. /// </summary>
  208. /// <value>The temp min C.</value>
  209. public string tempMinC { get; set; }
  210. /// <summary>
  211. /// Gets or sets the temp min F.
  212. /// </summary>
  213. /// <value>The temp min F.</value>
  214. public string tempMinF { get; set; }
  215. /// <summary>
  216. /// Gets or sets the weather code.
  217. /// </summary>
  218. /// <value>The weather code.</value>
  219. public string weatherCode { get; set; }
  220. /// <summary>
  221. /// Gets or sets the winddir16 point.
  222. /// </summary>
  223. /// <value>The winddir16 point.</value>
  224. public string winddir16Point { get; set; }
  225. /// <summary>
  226. /// Gets or sets the winddir degree.
  227. /// </summary>
  228. /// <value>The winddir degree.</value>
  229. public string winddirDegree { get; set; }
  230. /// <summary>
  231. /// Gets or sets the winddirection.
  232. /// </summary>
  233. /// <value>The winddirection.</value>
  234. public string winddirection { get; set; }
  235. /// <summary>
  236. /// Gets or sets the windspeed KMPH.
  237. /// </summary>
  238. /// <value>The windspeed KMPH.</value>
  239. public string windspeedKmph { get; set; }
  240. /// <summary>
  241. /// Gets or sets the windspeed miles.
  242. /// </summary>
  243. /// <value>The windspeed miles.</value>
  244. public string windspeedMiles { get; set; }
  245. protected static readonly CultureInfo UsCulture = new CultureInfo("en-US");
  246. /// <summary>
  247. /// To the weather forecast.
  248. /// </summary>
  249. /// <returns>WeatherForecast.</returns>
  250. public WeatherForecast ToWeatherForecast()
  251. {
  252. return new WeatherForecast
  253. {
  254. Date = DateTime.Parse(date, UsCulture),
  255. HighTemperatureCelsius = int.Parse(tempMaxC, UsCulture),
  256. HighTemperatureFahrenheit = int.Parse(tempMaxF, UsCulture),
  257. LowTemperatureCelsius = int.Parse(tempMinC, UsCulture),
  258. LowTemperatureFahrenheit = int.Parse(tempMinF, UsCulture),
  259. Condition = GetCondition(weatherCode)
  260. };
  261. }
  262. /// <summary>
  263. /// Gets the condition.
  264. /// </summary>
  265. /// <param name="weatherCode">The weather code.</param>
  266. /// <returns>WeatherConditions.</returns>
  267. public static WeatherConditions GetCondition(string weatherCode)
  268. {
  269. switch (weatherCode)
  270. {
  271. case "362":
  272. case "365":
  273. case "320":
  274. case "317":
  275. case "182":
  276. return WeatherConditions.Sleet;
  277. case "338":
  278. case "335":
  279. case "332":
  280. case "329":
  281. case "326":
  282. case "323":
  283. case "377":
  284. case "374":
  285. case "371":
  286. case "368":
  287. case "395":
  288. case "392":
  289. case "350":
  290. case "227":
  291. case "179":
  292. return WeatherConditions.Snow;
  293. case "314":
  294. case "311":
  295. case "308":
  296. case "305":
  297. case "302":
  298. case "299":
  299. case "296":
  300. case "293":
  301. case "284":
  302. case "281":
  303. case "266":
  304. case "263":
  305. case "359":
  306. case "356":
  307. case "353":
  308. case "185":
  309. case "176":
  310. return WeatherConditions.Rain;
  311. case "260":
  312. case "248":
  313. return WeatherConditions.Fog;
  314. case "389":
  315. case "386":
  316. case "200":
  317. return WeatherConditions.Thunderstorm;
  318. case "230":
  319. return WeatherConditions.Blizzard;
  320. case "143":
  321. return WeatherConditions.Mist;
  322. case "122":
  323. return WeatherConditions.Overcast;
  324. case "119":
  325. return WeatherConditions.Cloudy;
  326. case "115":
  327. return WeatherConditions.PartlyCloudy;
  328. default:
  329. return WeatherConditions.Sunny;
  330. }
  331. }
  332. }
  333. }