pyVisualCrossing 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ """Python Wrapper for Visual Crossing Weather API."""
2
+ from __future__ import annotations
3
+
4
+ from pyVisualCrossing.api import VisualCrossing
5
+ from pyVisualCrossing.data import ForecastData, ForecastDailyData, ForecastHourlyData
6
+
7
+ __title__ = "pyVisualCrossing"
8
+ __version__ = "0.1.0"
9
+ __author__ = "briis"
10
+ __license__ = "MIT"
@@ -0,0 +1,275 @@
1
+ """
2
+ This module contains the code to get weather data from
3
+ Visual Crossing API.
4
+ See: https://www.visualcrossing.com/
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import abc
9
+ import datetime
10
+ import json
11
+ import logging
12
+
13
+ from typing import List, Any, Dict
14
+ from urllib.request import urlopen
15
+
16
+ import aiohttp
17
+
18
+ from .const import SUPPORTED_LANGUAGES, VISUALCROSSING_BASE_URL
19
+ from .data import ForecastData, ForecastDailyData, ForecastHourlyData
20
+
21
+ UTC = datetime.timezone.utc
22
+
23
+ _LOGGER = logging.getLogger(__name__)
24
+
25
+ class VisualCrossingException(Exception):
26
+ """Exception thrown if failing to access API."""
27
+
28
+
29
+ class VisualCrossingAPIBase:
30
+ """
31
+ Baseclass to use as dependency injection pattern for easier
32
+ automatic testing
33
+ """
34
+
35
+ @abc.abstractmethod
36
+ def fetch_data(self, api_key: str, latitude: float, longitude: float, days: int, language: str) -> Dict[str, Any]:
37
+ """Override this"""
38
+ raise NotImplementedError(
39
+ "users must define fetch_data to use this base class"
40
+ )
41
+
42
+ @abc.abstractmethod
43
+ async def async_fetch_data(
44
+ api_key: str, latitude: float, longitude: float, days: int, language: str
45
+ ) -> Dict[str, Any]:
46
+ """Override this"""
47
+ raise NotImplementedError(
48
+ "users must define fetch_data to use this base class"
49
+ )
50
+
51
+ class VisualCrossingAPI(VisualCrossingAPIBase):
52
+ """Default implementation for WeatherFlow api"""
53
+
54
+ def __init__(self) -> None:
55
+ """Init the API with or without session"""
56
+ self.session = None
57
+
58
+ def fetch_data(self, api_key: str, latitude: float, longitude: float, days: int, language: str) -> Dict[str, Any]:
59
+ """Get data from API."""
60
+ api_url =f"{VISUALCROSSING_BASE_URL}{latitude},{longitude}/today/next{days}days?unitGroup=metric&key={api_key}&contentType=json&iconSet=icons2&lang={language}"
61
+ _LOGGER.debug("URL: %s", api_url)
62
+
63
+ response = urlopen(api_url)
64
+ data = response.read().decode("utf-8")
65
+ json_data = json.loads(data)
66
+
67
+ return json_data
68
+
69
+ async def async_fetch_data(self, api_key: str, latitude: float, longitude: float, days: int, language: str) -> Dict[str, Any]:
70
+ """Get data from API."""
71
+ api_url =f"{VISUALCROSSING_BASE_URL}{latitude},{longitude}/today/next{days}days?unitGroup=metric&key={api_key}&contentType=json&iconSet=icons2&lang={language}"
72
+
73
+ is_new_session = False
74
+ if self.session is None:
75
+ self.session = aiohttp.ClientSession()
76
+ is_new_session = True
77
+
78
+ async with self.session.get(api_url) as response:
79
+ if response.status != 200:
80
+ if is_new_session:
81
+ await self.session.close()
82
+ raise VisualCrossingException(
83
+ f"Failed to access Visual Crossing API with status code {response.status}"
84
+ )
85
+ data = await response.text()
86
+ if is_new_session:
87
+ await self.session.close()
88
+ return json.loads(data)
89
+
90
+ class VisualCrossing:
91
+ """
92
+ Class that uses the weather API from Visual Crossing
93
+ to retreive Weather Data for supplied Latitude and
94
+ longitude location
95
+ """
96
+
97
+ def __init__(
98
+ self,
99
+ api_key: str,
100
+ latitude: float,
101
+ longitude: float,
102
+ days: int = 14,
103
+ language: str = "en",
104
+ session: aiohttp.ClientSession = None,
105
+ api: VisualCrossingAPIBase =VisualCrossingAPI(),
106
+ ) -> None:
107
+ self._api_key = api_key
108
+ self._latitude = latitude
109
+ self._longitude = longitude
110
+ self._days = days
111
+ self._language = language
112
+ self._api = api
113
+ self._json_data = None
114
+
115
+ if days > 14:
116
+ self._days = 14
117
+
118
+ if session:
119
+ self._api.session = session
120
+
121
+ if language not in SUPPORTED_LANGUAGES:
122
+ self._language = "en"
123
+
124
+ def fetch_data(self) -> List[ForecastData]:
125
+ """Returns a list of weather data."""
126
+
127
+ if self._json_data is None:
128
+ self._json_data = self._api.fetch_data(self._api_key, self._latitude, self._longitude, self._days, self._language)
129
+
130
+ return _fetch_data(self._json_data)
131
+
132
+ async def async_fetch_data(self) -> List[ForecastData]:
133
+ """Returns a list of weather data."""
134
+
135
+ if self._json_data is None:
136
+ self._json_data = await self._api.async_fetch_data(self._api_key, self._latitude, self._longitude, self._days, self._language)
137
+
138
+ return _fetch_data(self._json_data)
139
+
140
+ def _fetch_data(api_result: dict) -> List[ForecastData]:
141
+ """Converts result from API to ForecastData List."""
142
+
143
+ # Add Current Condition Data
144
+ weather_data: ForecastData = _get_current_data(api_result)
145
+
146
+ forecast_daily = []
147
+ forecast_hourly = []
148
+
149
+ # Loop Through Records and add Daily and Hourly Forecast Data
150
+ for item in api_result["days"]:
151
+ valid_time = datetime.datetime.utcfromtimestamp(item["datetimeEpoch"]).replace(tzinfo=UTC)
152
+ condition = item.get("conditions", None)
153
+ cloudcover = item.get("cloudcover", None)
154
+ icon = item.get("icon", None)
155
+ temperature = item.get("tempmax", None)
156
+ temp_low = item.get("tempmin", None)
157
+ dew_point = item.get("dew", None)
158
+ apparent_temperature = item.get("feelslike", None)
159
+ precipitation = item.get("precip", None)
160
+ precipitation_probability = item.get("precipprob", None)
161
+ humidity = item.get("humidity", None)
162
+ pressure = item.get("pressure", None)
163
+ uv_index = item.get("uvindex", None)
164
+ wind_speed = item.get("windspeed", None)
165
+ wind_gust_speed = item.get("windgust", None)
166
+ wind_bearing = item.get("winddir", None)
167
+
168
+ day_data = ForecastDailyData(
169
+ valid_time,
170
+ temperature,
171
+ temp_low,
172
+ apparent_temperature,
173
+ condition,
174
+ icon,
175
+ cloudcover,
176
+ dew_point,
177
+ humidity,
178
+ precipitation_probability,
179
+ precipitation,
180
+ pressure,
181
+ wind_bearing,
182
+ wind_speed,
183
+ wind_gust_speed,
184
+ uv_index,
185
+ )
186
+ forecast_daily.append(day_data)
187
+
188
+ # Add Hourly data for this day
189
+ for row in item["hours"]:
190
+ valid_time = datetime.datetime.utcfromtimestamp(row["datetimeEpoch"]).replace(tzinfo=UTC)
191
+ condition = row.get("conditions", None)
192
+ cloudcover = row.get("cloudcover", None)
193
+ icon = row.get("icon", None)
194
+ temperature = row.get("temp", None)
195
+ dew_point = row.get("dew", None)
196
+ apparent_temperature = row.get("feelslike", None)
197
+ precipitation = row.get("precip", None)
198
+ precipitation_probability = row.get("precipprob", None)
199
+ humidity = row.get("humidity", None)
200
+ pressure = row.get("pressure", None)
201
+ uv_index = row.get("uvindex", None)
202
+ wind_speed = row.get("windspeed", None)
203
+ wind_gust_speed = row.get("windgust", None)
204
+ wind_bearing = row.get("winddir", None)
205
+
206
+ hour_data = ForecastHourlyData(
207
+ valid_time,
208
+ temperature,
209
+ apparent_temperature,
210
+ condition,
211
+ cloudcover,
212
+ icon,
213
+ dew_point,
214
+ humidity,
215
+ precipitation,
216
+ precipitation_probability,
217
+ pressure,
218
+ wind_bearing,
219
+ wind_gust_speed,
220
+ wind_speed,
221
+ uv_index,
222
+ )
223
+ forecast_hourly.append(hour_data)
224
+
225
+ weather_data.forecast_daily = forecast_daily
226
+ weather_data.forecast_hourly = forecast_hourly
227
+
228
+ return weather_data
229
+
230
+ # pylint: disable=R0914, R0912, W0212, R0915
231
+ def _get_current_data(api_result: dict) -> List[ForecastData]:
232
+ """Converts results from API to WeatherFlowForecast list"""
233
+
234
+ item = api_result["currentConditions"]
235
+
236
+ valid_time = datetime.datetime.utcfromtimestamp(item["datetimeEpoch"]).replace(tzinfo=UTC)
237
+ condition = item.get("conditions", None)
238
+ cloudcover = item.get("cloudcover", None)
239
+ icon = item.get("icon", None)
240
+ temperature = item.get("temp", None)
241
+ dew_point = item.get("dew", None)
242
+ apparent_temperature = item.get("feelslike", None)
243
+ precipitation = item.get("precip", None)
244
+ precipitation_probability = item.get("precipprob", None)
245
+ humidity = item.get("humidity", None)
246
+ solarradiation = item.get("solarradiation", None)
247
+ visibility = item.get("visibility", None)
248
+ pressure = item.get("pressure", None)
249
+ uv_index = item.get("uvindex", None)
250
+ wind_speed = item.get("windspeed", None)
251
+ wind_gust_speed = item.get("windgust", None)
252
+ wind_bearing = item.get("winddir", None)
253
+
254
+ current_condition = ForecastData(
255
+ valid_time,
256
+ apparent_temperature,
257
+ condition,
258
+ cloudcover,
259
+ dew_point,
260
+ humidity,
261
+ icon,
262
+ precipitation,
263
+ precipitation_probability,
264
+ pressure,
265
+ solarradiation,
266
+ temperature,
267
+ visibility,
268
+ uv_index,
269
+ wind_bearing,
270
+ wind_gust_speed,
271
+ wind_speed,
272
+ )
273
+
274
+ return current_condition
275
+
@@ -0,0 +1,5 @@
1
+ """System Wide constants for Visual Crossing Weather Wrapper."""
2
+ from __future__ import annotations
3
+
4
+ SUPPORTED_LANGUAGES = ["ar", "bg", "cs", "da", "de", "el", "en", "es", "fa", "fi", "fr", "he", "hu", "it", "ja", "ko", "nl", "pl", "pt", "sr", "sv", "tr", "uk", "vi", "zh"]
5
+ VISUALCROSSING_BASE_URL = "https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/"
@@ -0,0 +1,392 @@
1
+ """Holds the Data Classes for Visual Crossing Wrapper"""
2
+
3
+ from __future__ import annotations
4
+ from datetime import datetime
5
+ from typing import List
6
+
7
+ class ForecastData:
8
+ """Class to hold forecast data."""
9
+ # pylint: disable=R0913, R0902, R0914
10
+ def __init__(
11
+ self,
12
+ datetime: datetime,
13
+ apparent_temperature: float,
14
+ condition: str,
15
+ cloud_cover: int,
16
+ dew_point: float,
17
+ humidity: int,
18
+ icon: str,
19
+ precipitation: float,
20
+ precipitation_probability: int,
21
+ pressure: float,
22
+ solarradiation: float,
23
+ temperature: float,
24
+ visibility: int,
25
+ uv_index: int,
26
+ wind_bearing: int,
27
+ wind_gust_speed: float,
28
+ wind_speed: float,
29
+ forecast_daily: ForecastDailyData = None,
30
+ forecast_hourly: ForecastHourlyData = None,
31
+ ) -> None:
32
+ """Constructor"""
33
+ self._datetime = datetime
34
+ self._apparent_temperature = apparent_temperature
35
+ self._condition = condition
36
+ self._cloud_cover = cloud_cover
37
+ self._dew_point = dew_point
38
+ self._humidity = humidity
39
+ self._icon = icon
40
+ self._precipitation = precipitation
41
+ self._precipitation_probability = precipitation_probability
42
+ self._pressure = pressure
43
+ self._solarradiation = solarradiation
44
+ self._visibility = visibility
45
+ self._temperature = temperature
46
+ self._uv_index = uv_index
47
+ self._wind_bearing = wind_bearing
48
+ self._wind_gust_speed = wind_gust_speed
49
+ self._wind_speed = wind_speed
50
+ self._forecast_daily = forecast_daily
51
+ self._forecast_hourly = forecast_hourly
52
+
53
+
54
+ @property
55
+ def temperature(self) -> float:
56
+ """Air temperature (Celcius)"""
57
+ return self._temperature
58
+
59
+ @property
60
+ def dew_point(self) -> float:
61
+ """Dew Point (Celcius)"""
62
+ return self._dew_point
63
+
64
+ @property
65
+ def condition(self) -> str:
66
+ """Weather condition text."""
67
+ return self._condition
68
+
69
+ @property
70
+ def cloud_cover(self) -> int:
71
+ """Cloud Coverage."""
72
+ return self._cloud_cover
73
+
74
+ @property
75
+ def icon(self) -> str:
76
+ """Weather condition symbol."""
77
+ return self._icon
78
+
79
+ @property
80
+ def humidity(self) -> int:
81
+ """Humidity (%)."""
82
+ return self._humidity
83
+
84
+ @property
85
+ def apparent_temperature(self) -> float:
86
+ """Feels like temperature (Celcius)."""
87
+ return self._apparent_temperature
88
+
89
+ @property
90
+ def precipitation(self) -> float:
91
+ """Precipitation (mm)."""
92
+ return self._precipitation
93
+
94
+ @property
95
+ def precipitation_probability (self) -> int:
96
+ """Posobility of Precipiation (%)."""
97
+ return self._precipitation_probability
98
+
99
+ @property
100
+ def pressure(self) -> float:
101
+ """Sea Level Pressure (MB)"""
102
+ return self._pressure
103
+
104
+ @property
105
+ def solarradiation(self) -> float:
106
+ """Solar Radiation (w/m2)"""
107
+ return self._solarradiation
108
+
109
+ @property
110
+ def visibility(self) -> int:
111
+ """Visibility (km)"""
112
+ return self._visibility
113
+
114
+
115
+ @property
116
+ def wind_bearing(self) -> float:
117
+ """Wind bearing (degrees)"""
118
+ return self._wind_bearing
119
+
120
+ @property
121
+ def wind_gust_speed(self) -> float:
122
+ """Wind gust (m/s)"""
123
+ return self._wind_gust_speed
124
+
125
+ @property
126
+ def wind_speed(self) -> float:
127
+ """Wind speed (m/s)"""
128
+ return self._wind_speed
129
+
130
+ @property
131
+ def uv_index(self) -> float:
132
+ """UV Index"""
133
+ return self._uv_index
134
+
135
+ @property
136
+ def datetime(self) -> datetime:
137
+ """Valid time"""
138
+ return self._datetime
139
+
140
+ @property
141
+ def forecast_daily(self) -> ForecastDailyData:
142
+ """Forecast List"""
143
+ return self._forecast_daily
144
+
145
+ @forecast_daily.setter
146
+ def forecast_daily(self, new_forecast):
147
+ """Sets a new Value for forecast daily"""
148
+ self._forecast_daily = new_forecast
149
+
150
+ @property
151
+ def forecast_hourly(self) -> ForecastHourlyData:
152
+ """Forecast List"""
153
+ return self._forecast_hourly
154
+
155
+ @forecast_hourly.setter
156
+ def forecast_hourly(self, new_forecast):
157
+ """Sets a new Value for forecast hourly"""
158
+ self._forecast_hourly = new_forecast
159
+
160
+ class ForecastDailyData:
161
+ """Class to hold daily forecast data."""
162
+ # pylint: disable=R0913, R0902, R0914
163
+ def __init__(
164
+ self,
165
+ datetime: datetime,
166
+ temperature: float,
167
+ temp_low: float,
168
+ apparent_temperature: float,
169
+ condition: str,
170
+ icon: str,
171
+ cloud_cover: int,
172
+ dew_point: float,
173
+ humidity: int,
174
+ precipitation_probability: int,
175
+ precipitation: float,
176
+ pressure: float,
177
+ wind_bearing: int,
178
+ wind_speed: float,
179
+ wind_gust: float,
180
+ uv_index: int,
181
+ ) -> None:
182
+ """Constructor"""
183
+ self._datetime = datetime
184
+ self._temperature = temperature
185
+ self._temp_low = temp_low
186
+ self._apparent_temperature = apparent_temperature
187
+ self._condition = condition
188
+ self._cloud_cover = cloud_cover
189
+ self._dew_point = dew_point
190
+ self._humidity = humidity
191
+ self._icon = icon
192
+ self._precipitation_probability = precipitation_probability
193
+ self._precipitation = precipitation
194
+ self._pressure = pressure
195
+ self._wind_bearing = wind_bearing
196
+ self._wind_gust = wind_gust
197
+ self._wind_speed = wind_speed
198
+ self._uv_index = uv_index
199
+
200
+ @property
201
+ def datetime(self) -> datetime:
202
+ """Valid time"""
203
+ return self._datetime
204
+
205
+ @property
206
+ def temperature(self) -> float:
207
+ """Air temperature (Celcius)"""
208
+ return self._temperature
209
+
210
+ @property
211
+ def temp_low(self) -> float:
212
+ """Air temperature min during the day (Celcius)"""
213
+ return self._temp_low
214
+
215
+ @property
216
+ def apparent_temperature(self) -> float:
217
+ """Feels like temperature (Celcius)."""
218
+ return self._apparent_temperature
219
+
220
+ @property
221
+ def condition(self) -> str:
222
+ """Weather condition text."""
223
+ return self._condition
224
+
225
+ @property
226
+ def cloud_cover(self) -> int:
227
+ """Cloud Coverage."""
228
+ return self._cloud_cover
229
+
230
+ @property
231
+ def dew_point(self) -> float:
232
+ """Dew Point (Celcius)"""
233
+ return self._dew_point
234
+
235
+ @property
236
+ def humidity(self) -> int:
237
+ """Humidity (%)."""
238
+ return self._humidity
239
+
240
+ @property
241
+ def icon(self) -> str:
242
+ """Weather condition symbol."""
243
+ return self._icon
244
+
245
+ @property
246
+ def precipitation_probability (self) -> int:
247
+ """Posobility of Precipiation (%)."""
248
+ return self._precipitation_probability
249
+
250
+ @property
251
+ def precipitation(self) -> float:
252
+ """Precipitation (mm)."""
253
+ return self._precipitation
254
+
255
+ @property
256
+ def pressure(self) -> float:
257
+ """Sea Level Pressure (MB)"""
258
+ return self._pressure
259
+
260
+ @property
261
+ def uv_index(self) -> float:
262
+ """UV Index"""
263
+ return self._uv_index
264
+
265
+ @property
266
+ def wind_bearing(self) -> float:
267
+ """Wind bearing (degrees)"""
268
+ return self._wind_bearing
269
+
270
+ @property
271
+ def wind_gust(self) -> float:
272
+ """Wind Gust speed (m/s)"""
273
+ return self._wind_gust
274
+
275
+ @property
276
+ def wind_speed(self) -> float:
277
+ """Wind speed (m/s)"""
278
+ return self._wind_speed
279
+
280
+
281
+ class ForecastHourlyData:
282
+ """Class to hold hourly forecast data."""
283
+ # pylint: disable=R0913, R0902, R0914
284
+ def __init__(
285
+ self,
286
+ datetime: datetime,
287
+ temperature: float,
288
+ apparent_temperature: float,
289
+ condition: str,
290
+ cloud_cover: int,
291
+ icon: str,
292
+ dew_point: float,
293
+ humidity: int,
294
+ precipitation: float,
295
+ precipitation_probability: int,
296
+ pressure: float,
297
+ wind_bearing: float,
298
+ wind_gust_speed: int,
299
+ wind_speed: int,
300
+ uv_index: float,
301
+ ) -> None:
302
+ """Constructor"""
303
+ self._datetime = datetime
304
+ self._temperature = temperature
305
+ self._apparent_temperature = apparent_temperature
306
+ self._condition = condition
307
+ self._cloud_cover = cloud_cover
308
+ self._icon = icon
309
+ self._dew_point = dew_point
310
+ self._humidity = humidity
311
+ self._precipitation = precipitation
312
+ self._precipitation_probability = precipitation_probability
313
+ self._pressure = pressure
314
+ self._wind_bearing = wind_bearing
315
+ self._wind_gust_speed = wind_gust_speed
316
+ self._wind_speed = wind_speed
317
+ self._uv_index = uv_index
318
+
319
+ @property
320
+ def temperature(self) -> float:
321
+ """Air temperature (Celcius)"""
322
+ return self._temperature
323
+
324
+ @property
325
+ def condition(self) -> str:
326
+ """Weather condition text."""
327
+ return self._condition
328
+
329
+ @property
330
+ def cloud_cover(self) -> int:
331
+ """Cloud Coverage."""
332
+ return self._cloud_cover
333
+
334
+ @property
335
+ def dew_point(self) -> float:
336
+ """Dew Point (Celcius)"""
337
+ return self._dew_point
338
+
339
+ @property
340
+ def icon(self) -> str:
341
+ """Weather condition symbol."""
342
+ return self._icon
343
+
344
+ @property
345
+ def humidity(self) -> int:
346
+ """Humidity (%)."""
347
+ return self._humidity
348
+
349
+ @property
350
+ def apparent_temperature(self) -> float:
351
+ """Feels like temperature (Celcius)."""
352
+ return self._apparent_temperature
353
+
354
+ @property
355
+ def precipitation(self) -> float:
356
+ """Precipitation (mm)."""
357
+ return self._precipitation
358
+
359
+ @property
360
+ def precipitation_probability (self) -> int:
361
+ """Posobility of Precipiation (%)."""
362
+ return self._precipitation_probability
363
+
364
+ @property
365
+ def pressure(self) -> float:
366
+ """Sea Level Pressure (MB)"""
367
+ return self._pressure
368
+
369
+ @property
370
+ def wind_bearing(self) -> float:
371
+ """Wind bearing (degrees)"""
372
+ return self._wind_bearing
373
+
374
+ @property
375
+ def wind_gust_speed(self) -> float:
376
+ """Wind gust (m/s)"""
377
+ return self._wind_gust_speed
378
+
379
+ @property
380
+ def wind_speed(self) -> float:
381
+ """Wind speed (m/s)"""
382
+ return self._wind_speed
383
+
384
+ @property
385
+ def uv_index(self) -> float:
386
+ """UV Index"""
387
+ return self._uv_index
388
+
389
+ @property
390
+ def datetime(self) -> datetime:
391
+ """Valid time"""
392
+ return self._datetime
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Bjarne Riis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,83 @@
1
+ Metadata-Version: 2.1
2
+ Name: pyVisualCrossing
3
+ Version: 0.1.0
4
+ Summary: Gets the weather data from Visual Crossing
5
+ Home-page: https://github.com/briis/pyVisualCrossing
6
+ Author: briis
7
+ Author-email: bjarne@briis.com
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Development Status :: 4 - Beta
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+
16
+ # Python Wrapper for Visual Crossing Weather API
17
+
18
+ This Python Wrapper retrives data from the [Visual Crossing](https://www.visualcrossing.com/) API. Visual Crossing has an extensive Weather API for both historical and forecast weather data, and they have a Free Tier API Key which enables up to 1000 calls per day.
19
+
20
+ In order to get started you must create an Account with Visual Crossing and then create an API Key. You do this by accessing [this website](https://www.visualcrossing.com/weather-data-editions) and clicking on the **Free** plan. Then follow the instructions to create and account and store your key in a safe place.
21
+
22
+ ## Usage
23
+
24
+ Install the module by using this command in a terminal: `pip install pyVisualCrossing`
25
+
26
+ And then see `test_module.py` and `async_test_module.py` in the `samples` directory for usage examples, both standard and async.
27
+
28
+ ## Parameters
29
+
30
+ ```python
31
+ # Initialise the module
32
+ vcapi = VisualCrossing(
33
+ api_key,
34
+ latitude,
35
+ longitude,
36
+ days=7,
37
+ language="da"
38
+ )
39
+ ````
40
+
41
+ | Parameter | Required | Default | Description |
42
+ | --------- | -------- | ------- | ----------- |
43
+ | `api_key` | Yes | `None` | This is the API Key you signed up for from Visual Crossing. See above for instructions |
44
+ | `latitude` | Yes | `None` | Latitude for the location position |
45
+ | `longitude` | Yes | `None` | Longitude for the location position |
46
+ | `days` | No | `14` | Numbers of days to retrieve forecast for. 14 days means today plus the next 14 days. On the Free plan, this is the maximum number of days |
47
+ | `language` | No | `en` | The language in which text strings should be returned. Se below for list of valid languages. |
48
+ | `session` | No | `None` | A session variable. Only used when using the async function. |
49
+
50
+
51
+
52
+ For an in-depth description of the Visual Crossing API, go [here](https://www.visualcrossing.com/resources/documentation/weather-api/timeline-weather-api/)
53
+
54
+ ## Languages
55
+ Available languages include: ar (Arabic), bg (Bulgiarian), cs (Czech), da (Danish), de (German), el (Greek Modern), en (English), es (Spanish), fa (Farsi), fi (Finnish), fr (French), he (Hebrew), hu, (Hungarian), it (Italian), ja (Japanese), ko (Korean), nl (Dutch), pl (Polish), pt (Portuguese), ru (Russian),, sr (Serbian), sv (Swedish), tr (Turkish), uk (Ukranian), vi (Vietnamese) and zh (Chinese).
56
+
57
+ ## Icons
58
+ We use the Iconset *icons2*, which gives a more detailed description of the conditions.
59
+
60
+ | Icon id | Weather Conditions |
61
+ | -------------------- | ---------------------------- |
62
+ | snow | Amount of snow is greater than zero |
63
+ | snow-showers-day | Periods of snow during the day |
64
+ | snow-showers-night | Periods of snow during the night |
65
+ | thunder-rain | Thunderstorms throughout the day or night |
66
+ | thunder-showers-day | Possible thunderstorms throughout the day |
67
+ | thunder-showers-night | Possible thunderstorms throughout the night |
68
+ | rain | Amount of rainfall is greater than zero |
69
+ | showers-day | Rain showers during the day |
70
+ | showers-night | Rain showers during the night |
71
+ | fog | Visibility is low (lower than one kilometer or mile) |
72
+ | wind | Wind speed is high (greater than 30 kph or mph) |
73
+ | cloudy | Cloud cover is greater than 90% cover |
74
+ | partly-cloudy-day | Cloud cover is greater than 20% cover during day time. |
75
+ | partly-cloudy-night | Cloud cover is greater than 20% cover during night time. |
76
+ | clear-day | Cloud cover is less than 20% cover during day time |
77
+ | clear-night | Cloud cover is less than 20% cover during night time |
78
+
79
+ ## TODO
80
+
81
+ - Add all available items to the Data Structure
82
+ - Create `async_test_module.py` in the samples directory
83
+ - More detailed error handling.
@@ -0,0 +1,9 @@
1
+ pyVisualCrossing/__init__.py,sha256=gDdseMKZlvecfdCpAtaSL1jP-Stxh-pkviKcFpJk0NM,319
2
+ pyVisualCrossing/api.py,sha256=stl4kk8Ov8UUHjfU_r2tV4JVHijunVhRf5a8cPtbHeg,9261
3
+ pyVisualCrossing/const.py,sha256=8vhxvLIguiPPDB8h93z1j7OVpzHFjyrpvtgjSUZD4go,387
4
+ pyVisualCrossing/data.py,sha256=45uZ15AxefuyUrkEZ2bmihXQIsNfKM3CYG4vpwIwl6A,10500
5
+ pyVisualCrossing-0.1.0.dist-info/LICENSE,sha256=Z_3SNSdtSUo8UsGZ7hnBOXjDSTvFWEbUxNJxdRjaxLk,1068
6
+ pyVisualCrossing-0.1.0.dist-info/METADATA,sha256=sjaslhNN7NDC6zmahmKBpLE1oSLycM4bKSwyC_MBl2A,4298
7
+ pyVisualCrossing-0.1.0.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
8
+ pyVisualCrossing-0.1.0.dist-info/top_level.txt,sha256=hw0rVTorvfSv7hOAv0z8xq49056RxL4slkUaklJ0mOU,17
9
+ pyVisualCrossing-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.41.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ pyVisualCrossing