From b5dbc2c016a6f873fdb30d9c03928b306fa9ef29 Mon Sep 17 00:00:00 2001 From: Aptivi CEO Date: Tue, 11 Jun 2024 19:12:38 +0300 Subject: [PATCH] add - doc|prt - Finalized support for Weather.com --- We've finalized support for Weather.com! --- Type: add Breaking: False Doc Required: True Part: 2/2 --- Nettify/Weather/Examples/Example02-TWC.json | 1244 +++++++++++++++++++ Nettify/Weather/WeatherForecast.cs | 200 ++- Nettify/Weather/WeatherForecastInfo.cs | 49 +- Nettify/Weather/WeatherForecastOwm.cs | 37 +- 4 files changed, 1475 insertions(+), 55 deletions(-) create mode 100644 Nettify/Weather/Examples/Example02-TWC.json diff --git a/Nettify/Weather/Examples/Example02-TWC.json b/Nettify/Weather/Examples/Example02-TWC.json new file mode 100644 index 0000000..f1116ee --- /dev/null +++ b/Nettify/Weather/Examples/Example02-TWC.json @@ -0,0 +1,1244 @@ +{ + "calendarDayTemperatureMax": [ + 17, + 20, + 22, + 27, + 24, + 24, + 26, + 26, + 26, + 27, + 28, + 28, + 27, + 26, + 26 + ], + "calendarDayTemperatureMin": [ + 6, + 7, + 9, + 12, + 14, + 12, + 13, + 12, + 13, + 14, + 14, + 15, + 14, + 13, + 13 + ], + "dayOfWeek": [ + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Sunday", + "Monday" + ], + "expirationTimeUtc": [ + 1711372328, + 1711372328, + 1711372328, + 1711372328, + 1711372328, + 1711372328, + 1711372328, + 1711372328, + 1711372328, + 1711372328, + 1711372328, + 1711372328, + 1711372328, + 1711372328, + 1711372328 + ], + "moonPhase": [ + "Full Moon", + "Full Moon", + "Waning Gibbous", + "Waning Gibbous", + "Waning Gibbous", + "Waning Gibbous", + "Waning Gibbous", + "Waning Gibbous", + "Last Quarter", + "Waning Crescent", + "Waning Crescent", + "Waning Crescent", + "Waning Crescent", + "Waning Crescent", + "New Moon" + ], + "moonPhaseCode": [ + "F", + "F", + "WNG", + "WNG", + "WNG", + "WNG", + "WNG", + "WNG", + "LQ", + "WNC", + "WNC", + "WNC", + "WNC", + "WNC", + "N" + ], + "moonPhaseDay": [ + 15, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 27, + 28, + 29 + ], + "moonriseTimeLocal": [ + "2024-03-25T19:05:55+0300", + "2024-03-26T20:01:46+0300", + "2024-03-27T20:59:10+0300", + "2024-03-28T21:58:47+0300", + "2024-03-29T23:00:36+0300", + "", + "2024-03-31T00:03:34+0300", + "2024-04-01T01:05:17+0300", + "2024-04-02T02:03:21+0300", + "2024-04-03T02:55:13+0300", + "2024-04-04T03:39:55+0300", + "2024-04-05T04:19:09+0300", + "2024-04-06T04:53:27+0300", + "2024-04-07T05:24:46+0300", + "2024-04-08T05:55:44+0300" + ], + "moonriseTimeUtc": [ + 1711382755, + 1711472506, + 1711562350, + 1711652327, + 1711742436, + null, + 1711832614, + 1711922717, + 1712012601, + 1712102113, + 1712191195, + 1712279949, + 1712368407, + 1712456686, + 1712544944 + ], + "moonsetTimeLocal": [ + "2024-03-25T06:35:33+0300", + "2024-03-26T06:58:44+0300", + "2024-03-27T07:23:10+0300", + "2024-03-28T07:50:37+0300", + "2024-03-29T08:22:18+0300", + "2024-03-30T08:59:19+0300", + "2024-03-31T09:43:52+0300", + "2024-04-01T10:37:44+0300", + "2024-04-02T11:39:19+0300", + "2024-04-03T12:48:12+0300", + "2024-04-04T14:00:03+0300", + "2024-04-05T15:12:44+0300", + "2024-04-06T16:25:34+0300", + "2024-04-07T17:37:01+0300", + "2024-04-08T18:49:21+0300" + ], + "moonsetTimeUtc": [ + 1711337733, + 1711425524, + 1711513390, + 1711601437, + 1711689738, + 1711778359, + 1711867432, + 1711957064, + 1712047159, + 1712137692, + 1712228403, + 1712319164, + 1712409934, + 1712500621, + 1712591361 + ], + "narrative": [ + "Partly cloudy. Low 7C.", + "Sunshine. Highs 19 to 21C and lows 8 to 10C.", + "Cloudy. Highs 21 to 23C and lows 11 to 13C.", + "Plenty of sun. Highs 26 to 28C and lows 13 to 15C.", + "Afternoon showers. Highs 23 to 25C and lows 11 to 13C.", + "Mostly sunny. Highs 23 to 25C and lows 12 to 14C.", + "A few clouds. Highs 25 to 27C and lows 11 to 13C.", + "Plenty of sun. Highs 25 to 27C and lows 12 to 14C.", + "Plenty of sun. Highs 25 to 27C and lows 13 to 15C.", + "Mostly sunny. Highs 26 to 28C and lows 13 to 15C.", + "Mostly sunny. Highs 27 to 29C and lows 14 to 16C.", + "A few clouds. Highs 27 to 29C and lows 13 to 15C.", + "Times of sun and clouds. Highs 26 to 28C and lows 12 to 14C.", + "Mix of sun and clouds. Highs 25 to 27C and lows 12 to 14C.", + "Times of sun and clouds. Highs 25 to 27C and lows 13 to 15C." + ], + "qpf": [ + 0, + 0, + 0, + 0, + 0.85, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "qpfSnow": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "sunriseTimeLocal": [ + "2024-03-25T06:31:47+0300", + "2024-03-26T06:30:27+0300", + "2024-03-27T06:29:06+0300", + "2024-03-28T06:27:45+0300", + "2024-03-29T06:26:24+0300", + "2024-03-30T06:25:04+0300", + "2024-03-31T06:23:43+0300", + "2024-04-01T06:22:23+0300", + "2024-04-02T06:21:03+0300", + "2024-04-03T06:19:43+0300", + "2024-04-04T06:18:24+0300", + "2024-04-05T06:17:05+0300", + "2024-04-06T06:15:46+0300", + "2024-04-07T06:14:27+0300", + "2024-04-08T06:13:09+0300" + ], + "sunriseTimeUtc": [ + 1711337507, + 1711423827, + 1711510146, + 1711596465, + 1711682784, + 1711769104, + 1711855423, + 1711941743, + 1712028063, + 1712114383, + 1712200704, + 1712287025, + 1712373346, + 1712459667, + 1712545989 + ], + "sunsetTimeLocal": [ + "2024-03-25T18:50:35+0300", + "2024-03-26T18:51:19+0300", + "2024-03-27T18:52:03+0300", + "2024-03-28T18:52:46+0300", + "2024-03-29T18:53:30+0300", + "2024-03-30T18:54:14+0300", + "2024-03-31T18:54:57+0300", + "2024-04-01T18:55:40+0300", + "2024-04-02T18:56:24+0300", + "2024-04-03T18:57:07+0300", + "2024-04-04T18:57:51+0300", + "2024-04-05T18:58:34+0300", + "2024-04-06T18:59:17+0300", + "2024-04-07T19:00:00+0300", + "2024-04-08T19:00:44+0300" + ], + "sunsetTimeUtc": [ + 1711381835, + 1711468279, + 1711554723, + 1711641166, + 1711727610, + 1711814054, + 1711900497, + 1711986940, + 1712073384, + 1712159827, + 1712246271, + 1712332714, + 1712419157, + 1712505600, + 1712592044 + ], + "temperatureMax": [ + null, + 20, + 22, + 27, + 24, + 24, + 26, + 26, + 26, + 27, + 28, + 28, + 27, + 26, + 26 + ], + "temperatureMin": [ + 7, + 9, + 12, + 14, + 12, + 13, + 12, + 13, + 14, + 14, + 15, + 14, + 13, + 13, + 14 + ], + "validTimeLocal": [ + "2024-03-25T07:00:00+0300", + "2024-03-26T07:00:00+0300", + "2024-03-27T07:00:00+0300", + "2024-03-28T07:00:00+0300", + "2024-03-29T07:00:00+0300", + "2024-03-30T07:00:00+0300", + "2024-03-31T07:00:00+0300", + "2024-04-01T07:00:00+0300", + "2024-04-02T07:00:00+0300", + "2024-04-03T07:00:00+0300", + "2024-04-04T07:00:00+0300", + "2024-04-05T07:00:00+0300", + "2024-04-06T07:00:00+0300", + "2024-04-07T07:00:00+0300", + "2024-04-08T07:00:00+0300" + ], + "validTimeUtc": [ + 1711339200, + 1711425600, + 1711512000, + 1711598400, + 1711684800, + 1711771200, + 1711857600, + 1711944000, + 1712030400, + 1712116800, + 1712203200, + 1712289600, + 1712376000, + 1712462400, + 1712548800 + ], + "daypart": [ + { + "cloudCover": [ + null, + 24, + 15, + 52, + 85, + 23, + 8, + 83, + 72, + 36, + 22, + 33, + 29, + 23, + 26, + 25, + 24, + 23, + 28, + 34, + 28, + 24, + 24, + 34, + 34, + 45, + 44, + 46, + 42, + 45 + ], + "dayOrNight": [ + null, + "N", + "D", + "N", + "D", + "N", + "D", + "N", + "D", + "N", + "D", + "N", + "D", + "N", + "D", + "N", + "D", + "N", + "D", + "N", + "D", + "N", + "D", + "N", + "D", + "N", + "D", + "N", + "D", + "N" + ], + "daypartName": [ + null, + "Tonight", + "Tomorrow", + "Tomorrow night", + "Wednesday", + "Wednesday night", + "Thursday", + "Thursday night", + "Friday", + "Friday night", + "Saturday", + "Saturday night", + "Sunday", + "Sunday night", + "Monday", + "Monday night", + "Tuesday", + "Tuesday night", + "Wednesday", + "Wednesday night", + "Thursday", + "Thursday night", + "Friday", + "Friday night", + "Saturday", + "Saturday night", + "Sunday", + "Sunday night", + "Monday", + "Monday night" + ], + "iconCode": [ + null, + 29, + 32, + 27, + 26, + 29, + 34, + 26, + 39, + 29, + 34, + 33, + 34, + 33, + 34, + 33, + 34, + 33, + 34, + 29, + 34, + 33, + 34, + 29, + 30, + 29, + 30, + 29, + 30, + 29 + ], + "iconCodeExtend": [ + null, + 2900, + 3200, + 2700, + 2600, + 2900, + 3400, + 2600, + 7103, + 2900, + 3400, + 3300, + 3400, + 3300, + 3400, + 3300, + 3400, + 3300, + 3400, + 2900, + 3400, + 3300, + 3400, + 2900, + 3000, + 2900, + 3000, + 2900, + 3000, + 2900 + ], + "narrative": [ + null, + "Some clouds. Low 7C. Winds W at 15 to 30 km/h.", + "Mostly sunny. High near 20C. Winds WSW at 25 to 40 km/h.", + "Partly cloudy skies early will become overcast later during the night. Low 9C. Winds W at 15 to 25 km/h.", + "Cloudy. High 22C. Winds SSE at 10 to 15 km/h.", + "Some clouds early will give way to generally clear conditions overnight. Low 12C. Winds light and variable.", + "Generally sunny. High 27C. Winds S at 10 to 15 km/h.", + "Cloudy. Low 14C. Winds N at 10 to 15 km/h.", + "Cloudy in the morning, then off and on rain showers during the afternoon hours. High 24C. Winds ENE at 10 to 15 km/h. Chance of rain 40%.", + "A few clouds. Low 12C. Winds NNE at 10 to 15 km/h.", + "Mostly sunny skies. High 24C. Winds E at 10 to 15 km/h.", + "Mainly clear skies. Low 13C. Winds NNE at 10 to 15 km/h.", + "Generally sunny despite a few afternoon clouds. High 26C. Winds SE at 10 to 15 km/h.", + "Mostly clear skies. Low 12C. Winds N at 10 to 15 km/h.", + "Sunny along with a few clouds. Warm. High 26C. Winds ENE at 10 to 15 km/h.", + "A few clouds from time to time. Low 13C. Winds N at 10 to 15 km/h.", + "A few clouds from time to time. High 26C. Winds E at 10 to 15 km/h.", + "Mostly clear skies. Low 14C. Winds N at 10 to 15 km/h.", + "Mostly sunny skies. High 27C. Winds S at 10 to 15 km/h.", + "A few clouds from time to time. Low 14C. Winds light and variable.", + "Mostly sunny skies. High 28C. Winds SSW at 10 to 15 km/h.", + "Mostly clear skies. Low near 15C. Winds WNW at 10 to 15 km/h.", + "Except for a few afternoon clouds, mainly sunny. High 28C. Winds WSW at 15 to 25 km/h.", + "A few clouds. Low 14C. Winds W at 10 to 15 km/h.", + "Intervals of clouds and sunshine. High 27C. Winds WSW at 15 to 25 km/h.", + "A few clouds from time to time. Low 13C. Winds W at 10 to 15 km/h.", + "Intervals of clouds and sunshine. High 26C. Winds WSW at 15 to 25 km/h.", + "A few clouds from time to time. Low 13C. Winds W at 10 to 15 km/h.", + "Intervals of clouds and sunshine. High 26C. Winds SW at 10 to 15 km/h.", + "A few clouds. Low 14C. Winds W at 10 to 15 km/h." + ], + "precipChance": [ + null, + 5, + 5, + 3, + 4, + 0, + 0, + 1, + 39, + 24, + 19, + 5, + 11, + 9, + 16, + 11, + 15, + 6, + 2, + 2, + 5, + 0, + 0, + 0, + 0, + 7, + 1, + 13, + 12, + 1 + ], + "precipType": [ + null, + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain", + "rain" + ], + "qpf": [ + null, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0.85, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "qpfSnow": [ + null, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "qualifierCode": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "Q600", + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "qualifierPhrase": [ + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + "Warm.", + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + null + ], + "relativeHumidity": [ + null, + 62, + 49, + 65, + 46, + 50, + 32, + 44, + 40, + 61, + 47, + 54, + 38, + 48, + 36, + 47, + 35, + 45, + 31, + 42, + 32, + 41, + 29, + 39, + 28, + 41, + 30, + 46, + 33, + 45 + ], + "snowRange": [ + null, + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "temperature": [ + null, + 7, + 20, + 9, + 22, + 12, + 27, + 14, + 24, + 12, + 24, + 13, + 26, + 12, + 26, + 13, + 26, + 14, + 27, + 14, + 28, + 15, + 28, + 14, + 27, + 13, + 26, + 13, + 26, + 14 + ], + "temperatureHeatIndex": [ + null, + 16, + 20, + 15, + 22, + 18, + 27, + 22, + 24, + 19, + 24, + 21, + 26, + 21, + 26, + 21, + 26, + 21, + 27, + 22, + 28, + 23, + 28, + 23, + 27, + 22, + 26, + 21, + 26, + 22 + ], + "temperatureWindChill": [ + null, + 5, + 6, + 8, + 9, + 12, + 13, + 14, + 14, + 12, + 13, + 13, + 14, + 12, + 13, + 13, + 15, + 14, + 15, + 14, + 16, + 15, + 16, + 14, + 16, + 13, + 14, + 13, + 14, + 14 + ], + "thunderCategory": [ + null, + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder", + "No thunder" + ], + "thunderIndex": [ + null, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ], + "uvDescription": [ + null, + "Low", + "Very High", + "Low", + "Moderate", + "Low", + "Very High", + "Low", + "High", + "Low", + "Very High", + "Low", + "Very High", + "Low", + "Very High", + "Low", + "Very High", + "Low", + "Very High", + "Low", + "Very High", + "Low", + "Very High", + "Low", + "Very High", + "Low", + "Very High", + "Low", + "Very High", + "Low" + ], + "uvIndex": [ + null, + 0, + 8, + 0, + 3, + 0, + 8, + 0, + 6, + 0, + 8, + 0, + 8, + 0, + 8, + 0, + 8, + 0, + 8, + 0, + 8, + 0, + 8, + 0, + 8, + 0, + 8, + 0, + 8, + 0 + ], + "windDirection": [ + null, + 264, + 252, + 259, + 159, + 321, + 179, + 352, + 59, + 33, + 101, + 19, + 135, + 8, + 66, + 2, + 90, + 356, + 177, + 333, + 197, + 303, + 247, + 275, + 239, + 270, + 241, + 278, + 231, + 275 + ], + "windDirectionCardinal": [ + null, + "W", + "WSW", + "W", + "SSE", + "NW", + "S", + "N", + "ENE", + "NNE", + "E", + "NNE", + "SE", + "N", + "ENE", + "N", + "E", + "N", + "S", + "NNW", + "SSW", + "WNW", + "WSW", + "W", + "WSW", + "W", + "WSW", + "W", + "SW", + "W" + ], + "windPhrase": [ + null, + "Winds W at 15 to 30 km/h.", + "Winds WSW at 25 to 40 km/h.", + "Winds W at 15 to 25 km/h.", + "Winds SSE at 10 to 15 km/h.", + "Winds light and variable.", + "Winds S at 10 to 15 km/h.", + "Winds N at 10 to 15 km/h.", + "Winds ENE at 10 to 15 km/h.", + "Winds NNE at 10 to 15 km/h.", + "Winds E at 10 to 15 km/h.", + "Winds NNE at 10 to 15 km/h.", + "Winds SE at 10 to 15 km/h.", + "Winds N at 10 to 15 km/h.", + "Winds ENE at 10 to 15 km/h.", + "Winds N at 10 to 15 km/h.", + "Winds E at 10 to 15 km/h.", + "Winds N at 10 to 15 km/h.", + "Winds S at 10 to 15 km/h.", + "Winds light and variable.", + "Winds SSW at 10 to 15 km/h.", + "Winds WNW at 10 to 15 km/h.", + "Winds WSW at 15 to 25 km/h.", + "Winds W at 10 to 15 km/h.", + "Winds WSW at 15 to 25 km/h.", + "Winds W at 10 to 15 km/h.", + "Winds WSW at 15 to 25 km/h.", + "Winds W at 10 to 15 km/h.", + "Winds SW at 10 to 15 km/h.", + "Winds W at 10 to 15 km/h." + ], + "windSpeed": [ + null, + 28, + 32, + 19, + 10, + 8, + 10, + 11, + 15, + 12, + 15, + 10, + 14, + 11, + 14, + 11, + 12, + 10, + 13, + 10, + 15, + 11, + 17, + 12, + 19, + 14, + 20, + 14, + 17, + 13 + ], + "wxPhraseLong": [ + null, + "Partly Cloudy", + "Sunny", + "Mostly Cloudy", + "Cloudy", + "Partly Cloudy", + "Mostly Sunny", + "Cloudy", + "PM Showers", + "Partly Cloudy", + "Mostly Sunny", + "Mostly Clear", + "Mostly Sunny", + "Mostly Clear", + "Mostly Sunny", + "Mostly Clear", + "Mostly Sunny", + "Mostly Clear", + "Mostly Sunny", + "Partly Cloudy", + "Mostly Sunny", + "Mostly Clear", + "Mostly Sunny", + "Partly Cloudy", + "Partly Cloudy", + "Partly Cloudy", + "Partly Cloudy", + "Partly Cloudy", + "Partly Cloudy", + "Partly Cloudy" + ], + "wxPhraseShort": [ + null, + "P Cloudy", + "Sunny", + "M Cloudy", + "Cloudy", + "P Cloudy", + "M Sunny", + "Cloudy", + "PM Showers", + "P Cloudy", + "M Sunny", + "M Clear", + "M Sunny", + "M Clear", + "M Sunny", + "M Clear", + "M Sunny", + "M Clear", + "M Sunny", + "P Cloudy", + "M Sunny", + "M Clear", + "M Sunny", + "P Cloudy", + "P Cloudy", + "P Cloudy", + "P Cloudy", + "P Cloudy", + "P Cloudy", + "P Cloudy" + ] + } + ] +} diff --git a/Nettify/Weather/WeatherForecast.cs b/Nettify/Weather/WeatherForecast.cs index 75bb083..fc884c4 100644 --- a/Nettify/Weather/WeatherForecast.cs +++ b/Nettify/Weather/WeatherForecast.cs @@ -58,16 +58,17 @@ public static WeatherForecastInfo GetWeatherInfo(double latitude, double longitu /// A class containing properties of weather information internal static WeatherForecastInfo GetWeatherInfo(string WeatherURL, UnitMeasurement Unit = UnitMeasurement.Metric) { - string WeatherData; - JToken WeatherToken; Debug.WriteLine("Weather URL: {0} | Unit: {1}", WeatherURL, Unit); // Deal with measurements Unit = Unit == UnitMeasurement.Kelvin ? UnitMeasurement.Imperial : Unit; // Download and parse JSON data - WeatherData = WeatherDownloader.GetStringAsync(WeatherURL).Result; - WeatherToken = JToken.Parse(WeatherData); + WeatherDownloader.DefaultRequestHeaders.Add("Accept-Encoding", "gzip"); + var stream = WeatherDownloader.GetStreamAsync(WeatherURL).Result; + WeatherDownloader.DefaultRequestHeaders.Remove("Accept-Encoding"); + string uncompressed = Uncompress(stream); + JToken WeatherToken = JToken.Parse(uncompressed); return FinalizeInstallation(WeatherToken, Unit); } @@ -93,32 +94,166 @@ public static async Task GetWeatherInfoAsync(double latitud /// A class containing properties of weather information internal static async Task GetWeatherInfoAsync(string WeatherURL, UnitMeasurement Unit = UnitMeasurement.Metric) { - string WeatherData; - JToken WeatherToken; Debug.WriteLine("Weather URL: {0} | Unit: {1}", WeatherURL, Unit); // Deal with measurements Unit = Unit == UnitMeasurement.Kelvin ? UnitMeasurement.Imperial : Unit; // Download and parse JSON data - WeatherData = await WeatherDownloader.GetStringAsync(WeatherURL); - WeatherToken = JToken.Parse(WeatherData); + WeatherDownloader.DefaultRequestHeaders.Add("Accept-Encoding", "gzip"); + var stream = await WeatherDownloader.GetStreamAsync(WeatherURL); + WeatherDownloader.DefaultRequestHeaders.Remove("Accept-Encoding"); + string uncompressed = Uncompress(stream); + JToken WeatherToken = JToken.Parse(uncompressed); return FinalizeInstallation(WeatherToken, Unit); } internal static WeatherForecastInfo FinalizeInstallation(JToken WeatherToken, UnitMeasurement Unit = UnitMeasurement.Metric) { - WeatherForecastInfo WeatherInfo = new() + // Get the adjusted data + T Adjust(string dayPartData) { - // Put needed data to the class - // TODO: Handle weather condition translation - Weather = (WeatherCondition)WeatherToken.SelectToken("weather").First.SelectToken("id").ToObject(typeof(WeatherCondition)), - Temperature = (double)WeatherToken["daypart"]["temperature"][1].ToObject(typeof(double)), - Humidity = (double)WeatherToken["daypart"]["humidity"][1].ToObject(typeof(double)), - WindSpeed = (double)WeatherToken["daypart"]["windSpeed"][1].ToObject(typeof(double)), - WindDirection = (double)WeatherToken["daypart"]["windDirection"][1].ToObject(typeof(double)), - TemperatureMeasurement = Unit - }; + var dayPartArray = WeatherToken["daypart"][0][dayPartData]; + var adjusted = dayPartArray[0]; + if (adjusted.Type == JTokenType.Null) + adjusted = dayPartArray[1]; + return (T)adjusted.ToObject(typeof(T)); + } + + // Now, get the necessary variables to get the weather condition info + long iconCode = Adjust("iconCode"); + WeatherCondition cond = WeatherCondition.Clear; + switch (iconCode) + { + case 0: + // Tornado + cond = WeatherCondition.Tornado; + break; + case 3: + // Strong storms + cond = WeatherCondition.HeavyThunderstorm; + break; + case 4: + // Thunderstorms + cond = WeatherCondition.Thunderstorm; + break; + case 5: + case 7: + // Rain / Snow (5) - Wintry Mix (7) + cond = WeatherCondition.RainAndSnow; + break; + case 6: + // Rain / Sleet + cond = WeatherCondition.Sleet; + break; + case 8: + // Freezing Drizzle + cond = WeatherCondition.HeavyDrizzle; + break; + case 9: + // Drizzle + cond = WeatherCondition.Drizzle; + break; + case 10: + // Freezing Rain + cond = WeatherCondition.FreezingRain; + break; + case 11: + // Showers + cond = WeatherCondition.ShowerRain; + break; + case 12: + // Rain + cond = WeatherCondition.LightRain; + break; + case 13: + // Flurries + cond = WeatherCondition.LightSnow; + break; + case 15: + case 16: + // Blowing/Drifting Snow (15) - Snow (16) + cond = WeatherCondition.Snow; + break; + case 17: + // Hail + cond = WeatherCondition.LightShowerSleet; + break; + case 18: + // Sleet + cond = WeatherCondition.Sleet; + break; + case 19: + // Sandstorm + cond = WeatherCondition.Sand; + break; + case 20: + // Foggy + cond = WeatherCondition.Fog; + break; + case 21: + // Haze + cond = WeatherCondition.Haze; + break; + case 22: + // Smoke + cond = WeatherCondition.Smoke; + break; + case 27: + case 28: + // Mostly Cloudy (27, 28) + cond = WeatherCondition.MostlyCloudy; + break; + case 29: + case 30: + // Partly Cloudy (29, 30) + cond = WeatherCondition.PartlyCloudy; + break; + case 26: + case 33: + case 34: + // Cloudy (26) - Fair (33, 34) + cond = WeatherCondition.FewClouds; + break; + case 35: + // Mixed rain and hail + cond = WeatherCondition.ModerateRain; + break; + case 37: + case 38: + case 47: + // Isolated thunderstorms (37) - Scattered thunderstorms (38, 47) + cond = WeatherCondition.RaggedThunderstorm; + break; + case 39: + case 45: + // Scattered showers (39, 45) + cond = WeatherCondition.RaggedShowerRain; + break; + case 40: + // Heavy rain + cond = WeatherCondition.HeavyRain; + break; + case 14: + case 41: + case 46: + // Snow showers (14) - Scattered snow showers (41, 46) + cond = WeatherCondition.ShowerSnow; + break; + case 42: + case 43: + // Heavy snow (42) - Blizzard (43) + cond = WeatherCondition.HeavySnow; + break; + } + + // Finally, create the forecast info instance + var temperature = Adjust("temperature"); + var humidity = Adjust("qpf"); + var windSpeed = Adjust("windSpeed"); + var windDirection = Adjust("windDirection"); + var temperatureMeasurement = Unit; + WeatherForecastInfo WeatherInfo = new(cond, temperatureMeasurement, temperature, humidity, windSpeed, windDirection, WeatherToken, WeatherServerType.TheWeatherChannel); return WeatherInfo; } @@ -132,7 +267,9 @@ internal static WeatherForecastInfo FinalizeInstallation(JToken WeatherToken, Un Debug.WriteLine("Weather City List URL: {0}", WeatherCityListURL); // Open the stream to the city list URL + WeatherDownloader.DefaultRequestHeaders.Add("Accept-Encoding", "gzip"); WeatherCityListDataStream = WeatherDownloader.GetStreamAsync(WeatherCityListURL).Result; + WeatherDownloader.DefaultRequestHeaders.Remove("Accept-Encoding"); return FinalizeCityList(WeatherCityListDataStream); } @@ -146,16 +283,16 @@ internal static WeatherForecastInfo FinalizeInstallation(JToken WeatherToken, Un Debug.WriteLine("Weather City List URL: {0}", WeatherCityListURL); // Open the stream to the city list URL + WeatherDownloader.DefaultRequestHeaders.Add("Accept-Encoding", "gzip"); WeatherCityListDataStream = await WeatherDownloader.GetStreamAsync(WeatherCityListURL); + WeatherDownloader.DefaultRequestHeaders.Remove("Accept-Encoding"); return FinalizeCityList(WeatherCityListDataStream); } internal static Dictionary FinalizeCityList(Stream WeatherCityListDataStream) { - // Get the token - var reader = new StreamReader(WeatherCityListDataStream); - string json = reader.ReadToEnd(); - var token = JToken.Parse(json); + string uncompressed = Uncompress(WeatherCityListDataStream); + JToken token = JToken.Parse(uncompressed); // Get the addresses, the latitudes, and the longitudes var loc = token["location"]; @@ -177,5 +314,24 @@ internal static WeatherForecastInfo FinalizeInstallation(JToken WeatherToken, Un // Return list return cities; } + + internal static string Uncompress(Stream compressedDataStream) + { + GZipStream compressedData; + var compressedUncompressed = new List(); + int compressedReadByte = 0; + + // Parse the weather list JSON. Since the output is gzipped, we'll have to uncompress it using stream, since the city list + // is large anyways. This saves you from downloading full 45+ MB of text. + compressedData = new GZipStream(compressedDataStream, CompressionMode.Decompress, false); + while (compressedReadByte != -1) + { + compressedReadByte = compressedData.ReadByte(); + if (compressedReadByte != -1) + compressedUncompressed.Add((byte)compressedReadByte); + } + + return Encoding.Default.GetString([.. compressedUncompressed]); + } } } diff --git a/Nettify/Weather/WeatherForecastInfo.cs b/Nettify/Weather/WeatherForecastInfo.cs index 0d73a31..22814bd 100644 --- a/Nettify/Weather/WeatherForecastInfo.cs +++ b/Nettify/Weather/WeatherForecastInfo.cs @@ -17,6 +17,8 @@ // along with this program. If not, see . // +using Newtonsoft.Json.Linq; +using System; using System.Diagnostics; namespace Nettify.Weather @@ -30,27 +32,47 @@ public partial class WeatherForecastInfo /// /// Weather condition /// - public WeatherCondition Weather { get; set; } + public WeatherCondition Weather { get; } /// /// Temperature measurement /// - public UnitMeasurement TemperatureMeasurement { get; set; } + public UnitMeasurement TemperatureMeasurement { get; } /// /// Temperature /// - public double Temperature { get; set; } + public double Temperature { get; } /// /// Humidity in percent /// - public double Humidity { get; set; } + public double Humidity { get; } /// /// Wind speed. Imperial: mph, Metric/Kelvin: m.s /// - public double WindSpeed { get; set; } + public double WindSpeed { get; } /// /// Wind direction in degrees /// - public double WindDirection { get; set; } + public double WindDirection { get; } + /// + /// Weather token + /// + public JToken WeatherToken { get; } + /// + /// Whether the server type is OWM or TWC + /// + public WeatherServerType ServerType { get; } + + internal WeatherForecastInfo(WeatherCondition weather, UnitMeasurement temperatureMeasurement, double temperature, double humidity, double windSpeed, double windDirection, JToken weatherToken, WeatherServerType serverType) + { + Weather = weather; + TemperatureMeasurement = temperatureMeasurement; + Temperature = temperature; + Humidity = humidity; + WindSpeed = windSpeed; + WindDirection = windDirection; + WeatherToken = weatherToken ?? throw new ArgumentNullException(nameof(weatherToken)); + ServerType = serverType; + } } /// @@ -309,4 +331,19 @@ public enum WeatherCondition /// MostlyCloudy } + + /// + /// Weather server type + /// + public enum WeatherServerType + { + /// + /// OpenWeatherMap + /// + OpenWeatherMap, + /// + /// The Weather Channel + /// + TheWeatherChannel, + } } diff --git a/Nettify/Weather/WeatherForecastOwm.cs b/Nettify/Weather/WeatherForecastOwm.cs index d192366..cec7449 100644 --- a/Nettify/Weather/WeatherForecastOwm.cs +++ b/Nettify/Weather/WeatherForecastOwm.cs @@ -137,16 +137,13 @@ internal static async Task GetWeatherInfoAsync(string Weath internal static WeatherForecastInfo FinalizeInstallation(JToken WeatherToken, UnitMeasurement Unit = UnitMeasurement.Metric) { - WeatherForecastInfo WeatherInfo = new() - { - // Put needed data to the class - Weather = (WeatherCondition)WeatherToken.SelectToken("weather").First.SelectToken("id").ToObject(typeof(WeatherCondition)), - Temperature = (double)WeatherToken.SelectToken("main").SelectToken("temp").ToObject(typeof(double)), - Humidity = (double)WeatherToken.SelectToken("main").SelectToken("humidity").ToObject(typeof(double)), - WindSpeed = (double)WeatherToken.SelectToken("wind").SelectToken("speed").ToObject(typeof(double)), - WindDirection = (double)WeatherToken.SelectToken("wind").SelectToken("deg").ToObject(typeof(double)), - TemperatureMeasurement = Unit - }; + var weather = (WeatherCondition)WeatherToken.SelectToken("weather").First.SelectToken("id").ToObject(typeof(WeatherCondition)); + var temperature = (double)WeatherToken.SelectToken("main").SelectToken("temp").ToObject(typeof(double)); + var humidity = (double)WeatherToken.SelectToken("main").SelectToken("humidity").ToObject(typeof(double)); + var windSpeed = (double)WeatherToken.SelectToken("wind").SelectToken("speed").ToObject(typeof(double)); + var windDirection = (double)WeatherToken.SelectToken("wind").SelectToken("deg").ToObject(typeof(double)); + var temperatureMeasurement = Unit; + WeatherForecastInfo WeatherInfo = new(weather, temperatureMeasurement, temperature, humidity, windSpeed, windDirection, WeatherToken, WeatherServerType.OpenWeatherMap); return WeatherInfo; } @@ -180,26 +177,12 @@ public static async Task> ListAllCitiesAsync() internal static Dictionary FinalizeCityList(Stream WeatherCityListDataStream) { - GZipStream WeatherCityListData; - var WeatherCityListUncompressed = new List(); - int WeatherCityListReadByte = 0; - JToken WeatherCityListToken; var WeatherCityList = new Dictionary(); - - // Parse the weather list JSON. Since the output is gzipped, we'll have to uncompress it using stream, since the city list - // is large anyways. This saves you from downloading full 45+ MB of text. - WeatherCityListData = new GZipStream(WeatherCityListDataStream, CompressionMode.Decompress, false); - while (WeatherCityListReadByte != -1) - { - WeatherCityListReadByte = WeatherCityListData.ReadByte(); - if (WeatherCityListReadByte != -1) - WeatherCityListUncompressed.Add((byte)WeatherCityListReadByte); - } - - WeatherCityListToken = JToken.Parse(Encoding.Default.GetString([.. WeatherCityListUncompressed])); + string uncompressed = WeatherForecast.Uncompress(WeatherCityListDataStream); + JToken WeatherToken = JToken.Parse(uncompressed); // Put needed data to the class - foreach (JToken WeatherCityToken in WeatherCityListToken) + foreach (JToken WeatherCityToken in WeatherToken) { long cityId = (long)WeatherCityToken["id"]; string cityName = (string)WeatherCityToken["name"];