├── .gitignore ├── output-example.png ├── LICENSE ├── README.md └── forecast.py /.gitignore: -------------------------------------------------------------------------------- 1 | venv/ 2 | *.pyc 3 | *.tar.gz 4 | .DS_Store 5 | ehthumbs.db 6 | Icon? 7 | Thumbs.db 8 | .idea -------------------------------------------------------------------------------- /output-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gonzaloplaza/python-weather-forecast/HEAD/output-example.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Gonzalo Plaza 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python Weather Forecast 2 | ### version 1.0.0 3 | Weather Forecast is a simple Python 3 console program to get Weather Forecast from DarkSky.net service API using any address as parameter. 4 | 5 | - It uses Google Maps Geocoding API to transform any string address into numeric coordinates. 6 | - It obtains weekly forecast and related weather information for any coordinates in the World. 7 | - Output language and metric system are configurables parameters. 8 | 9 | > Note: This program has been developed using Python 3.5.2. It's NOT compatible with Python 2.7 versions. 10 | 11 | ### Requirements 12 | 13 | In order to get the weather forecast information from external services,you'll need to sign up and obtain your own API Key: 14 | * Python 3.5.* installed in your OS. 15 | * DarkSky.net API Key: You can obtain your own here: https://darksky.net/dev/ 16 | * Google Maps API Key - It's optional for development purposes, but you'll need to get your own key here: https://developers.google.com/maps/documentation/geocoding/get-api-key 17 | 18 | ### Installation (for Linux OS) 19 | 20 | You must have to declare **DS_API_KEY** (DarkSky) and **GM_API_KEY** as environment variables. Note that GM_API_KEY is optional for development purposes, you don't need to declare. 21 | 22 | ```sh 23 | $ export DS_API_KEY=your_api_key_obtained_from_darksky 24 | $ export GM_API_KEY=your_api_key_obtained_from_google 25 | ``` 26 | Download the project from this repository: 27 | ```sh 28 | $ git clone https://github.com/gonzaloplaza/python-weather-forecast.git my-project 29 | ``` 30 | 31 | ### Configuration 32 | You can change the main language for output information using ISO codes. By default, language variable (**LANG**) is "en". 33 | 34 | You can change the default code for **UNITS** variable that is "si" (International System). Available codes are: 35 | - **auto**: automatically select units based on geographic location 36 | - **ca**: same as si, except that windSpeed is in kilometers per hour 37 | - **uk2**: same as si, except that nearestStormDistance and visibility are in miles and windSpeed is in miles per hour 38 | - **us**: Imperial units 39 | - **si**: SI units (default) 40 | 41 | You can find a list of available languages and unit codes here: https://darksky.net/dev/docs/forecast 42 | 43 | ### Usage 44 | Once you have declared environment variables, you can execute the console program: 45 | 46 | ```sh 47 | $ cd my-project 48 | $ python3 forecast.py "Gran Via Street 28,Madrid" 49 | ``` 50 | And you'll get forecast information as output!: 51 | ![Output Example](http://ordermin.com/images/python-weather-forecast-output.png) 52 | 53 | > Note: Forecast API is free until 1000 requests per day. For more information, check their FAQ: https://darksky.net/dev/docs/faq 54 | 55 | ### Contributing 56 | Feel free to contribute to this project, pull requests and other improvements are welcome. If you have any ideas, just open an issue and tell me what you think, or send me an email to hello (at) ordermin.com 57 | 58 | ### Licensing 59 | 60 | The code in this project is licensed under [MIT LICENSE](https://github.com/gonzaloplaza/python-weather-forecast/blob/master/LICENSE). Read file for more information. 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /forecast.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import sys 5 | import requests 6 | from datetime import datetime 7 | 8 | # Global Parameters 9 | LANG = 'en' 10 | 11 | # DarkSky.net API Parameters 12 | DS_API_HOST = 'https://api.darksky.net/forecast' 13 | DS_API_KEY = os.environ.get('DS_API_KEY') 14 | DS_UNITS = 'si' 15 | 16 | # Google Maps Geocoding API Parameters 17 | GM_ENDPOINT = 'http://maps.google.com/maps/api/geocode/json' 18 | GM_API_KEY = os.environ.get('GM_API_KEY') 19 | 20 | 21 | def make_get_request(uri: str, payload): 22 | """ 23 | Function to make a GET request to API Endpoint 24 | :param uri: 25 | :param payload: 26 | :return: 27 | """ 28 | response = requests.get(uri, payload) 29 | if response.status_code != 200: 30 | return None 31 | else: 32 | return response.json() 33 | 34 | 35 | def get_geo_data(address: str): 36 | """ Function to get coordinates from Google Maps Geocoding API 37 | :param address: 38 | :return: 39 | """ 40 | payload = {'address': address, 'language': LANG, 'key': GM_API_KEY} 41 | response = make_get_request(GM_ENDPOINT, payload) 42 | 43 | if not response: 44 | return None 45 | 46 | data = response['results'][0] 47 | formatted_address = data['formatted_address'] 48 | lat = data['geometry']['location']['lat'] 49 | lng = data['geometry']['location']['lng'] 50 | 51 | return {'lat': lat, 'lng': lng, 'formatted_address': formatted_address} 52 | 53 | 54 | def get_forecast_data(lat: str, lng: str): 55 | """ Function to get Forecast data from DarkSky.net API 56 | :param lat: 57 | :param lng: 58 | :return: 59 | """ 60 | uri = DS_API_HOST + '/' + DS_API_KEY + '/' + str(lat) + ',' + str(lng) 61 | payload = {'lang': LANG, 'units': DS_UNITS} 62 | response = make_get_request(uri, payload) 63 | 64 | if not response: 65 | return None 66 | 67 | return response['daily'] 68 | 69 | 70 | def print_daily_forecast(geo, forecast): 71 | """ 72 | Function to print daily weather forecast information 73 | :param geo: 74 | :param forecast: 75 | """ 76 | print('Getting Forecast for: ' + geo['formatted_address']) 77 | print('Weekly Summary: ' + forecast['summary']) 78 | print() 79 | 80 | for day in forecast['data']: 81 | date = datetime.fromtimestamp(day['time']) 82 | 83 | if date.date() == datetime.now().date(): 84 | day_name = 'Today' 85 | else: 86 | day_name = date.strftime("%A") 87 | 88 | summary = day['summary'] 89 | temperature_min = str(round(day['temperatureMin'])) + 'ºC' 90 | temperature_max = str(round(day['temperatureMax'])) + 'ºC' 91 | print( 92 | date.strftime('%d/%m/%Y') + ' (' + day_name + '): ' + 93 | summary + ' ' + temperature_min + ' - ' + temperature_max 94 | ) 95 | print() 96 | 97 | 98 | def print_header(): 99 | print('---------------------------------') 100 | print(' WEATHER FORECAST 1.O ') 101 | print('---------------------------------') 102 | print() 103 | 104 | 105 | def main(): 106 | """ 107 | Main Function 108 | """ 109 | if len(sys.argv) < 2 or DS_API_KEY is None: 110 | exit('Error: no location or env vars found') 111 | 112 | geo_data = get_geo_data(sys.argv[1]) 113 | 114 | if not geo_data: 115 | exit('Error: Address not found or invalid response') 116 | 117 | forecast_data = get_forecast_data(geo_data['lat'], geo_data['lng']) 118 | 119 | if not forecast_data: 120 | exit('Error: Forecast not found or invalid response') 121 | 122 | # Print Output Forecast information 123 | print_header() 124 | print_daily_forecast(geo_data, forecast_data) 125 | 126 | 127 | if __name__ == '__main__': 128 | main() 129 | --------------------------------------------------------------------------------