Since I am going to have a 5-day trip to Sapporo, Hokkaido, Japan at the end of August, I would like to have a weather forecast for my trip.
“So why don’t you check from a weather forecast site for free?”
Yes, but I would like to get the exact information that I want to know. And it is easy to do when we do it in Python. Check on web is free, do it yourself is just, priceless.
Okay, talk is cheap, let’s do it. Like the time we did the 10 lines fx tool, we should keep our code short and simple.
As we are doing weather forecast operation and we are no weather guys, we need an API and its key to do the weather job for us. Then we have the Dark Sky weather API. It is fast and simple, and the first 1000 API calls per day are free, it is pretty enough for our weather tool. So just go there to get the API key for free.
Design the Interface
I would like to make a python program with command line user interface. Since it is a weather forecast tool for vacation, we have following things as input parameters:
- start date
- end date
The expected command should look like:
python weather_tool.py [destination] [start date] [end date]
And the result should look like:
Location: [Date of Day 1] [Weather info of Day 1] ...... [Date of Day N] [Weather info of Day N]
First of all, let we install our required modules. Again, we use our good old friend, pip. Other then checking the source code to find related modules and install them one by one, in Python, we can take advantage of a “requirements.txt” file. A “requirements.txt” file is a list of python modules to be installed by pip in plain text format. So we can put all our required modules in a “requirements.txt”, and let pip to install and setup our development environment.
pip install -r requirements.txt
Inside the Code
As usual, we import required modules at the top of our program:
from geopy.geocoders import Nominatim from datetime import datetime,timedelta import sys, requests
This time, we use geopy python module to get location information such as address, latitude and longitude.
DARK_SKY_API_KEY = "YOUR_DARK_SKY_API_KEY_HERE" option_list = "exclude=currently,minutely,hourly,alerts&units=si"
Fill you Dark Sky API KEY on line 4. And you can change Celsius/Fahrenheit setting on “units” at line 5.
location = Nominatim().geocode(sys.argv, language='en_US') d_from_date = datetime.strptime(sys.argv , '%Y-%m-%d') d_to_date = datetime.strptime(sys.argv , '%Y-%m-%d')
We get the destination, start date and end date from the command line arguments. Please note that both start date and end date are in “YYYY-MM-DD” format.
delta = d_to_date - d_from_date latitude = str(location.latitude) longitude = str(location.longitude)
Now we calculate the number of day between start date and end date, and get the latitude and longitude using Nominatim tool from OpenStreetMap.org.
The Weather Forecast Magic Starts Here
We have API key, location and the date range. What we do next is just call the Dark Sky API, then sit back, grab a popcorn and let the API do the weather forecast magic for us.
print("\nLocation: "+ location.address) for i in range(delta.days+1): new_date = (d_from_date + timedelta(days=i)).strftime('%Y-%m-%d') search_date = new_date+"T00:00:00" response = requests.get("https://api.darksky.net/forecast/"+DARK_SKY_API_KEY+"/"+latitude+","+longitude+","+search_date+"?"+option_list) json_res = response.json()
We use a for loop with the day range of our start date and end date, then make a call to the Dark Sky API. Please note that a timedelta object is used to create the time duration, i.e.
- d_from_date + timedelta(days=1) will be one day after d_from_date
- d_from_date + timedelta(days=3) will be three days after d_from_date
After sending the latitude, longitude and the date to the Dark Sky API, it will return a JSON object with weather information and we pick our information from it.
print("\n"+(d_from_date + timedelta(days=i)).strftime('%Y-%m-%d %A')) unit_type = '°F' if json_res['flags']['units'] == 'us' else '°C' print("Min temperature: "+str(json_res['daily']['data']['apparentTemperatureMin'])+unit_type) print("Max temperature: "+str(json_res['daily']['data']['apparentTemperatureMax'])+unit_type) print("Summary: " + json_res['daily']['data']['summary']) precip_type = None precip_prob = None if'precipProbability' in json_res['daily']['data'] and 'precipType' in json_res['daily']['data']: precip_type = json_res['daily']['data']['precipType'] precip_prob = json_res['daily']['data']['precipProbability'] if (precip_type == 'rain' and precip_prob != None): precip_prob *= 100 print("Chance of rain: %.2f%%" % (precip_prob))
Like I have mentioned before, I would like to get only the information I am interested. Thus I have both the max and min-imum “feel like” temperatures, a daily summary and the chance of rain. The Dark Sky JSON object contains much more information, you can check out their document to add the information you need.
The programming part is all done, it is time to run our program. As I said, I will go to Sapporo at the end of August, then I can input:
python weather_tool.py Sapporo 2017-08-30 2017-09-03
And we got:
Location: Sapporo, Ishikari, Hokkaido, Japan 2017-08-30 Wednesday Min temperature: 18.47°C Max temperature: 23.84°C Summary: Mostly cloudy throughout the day. ........ 2017-09-03 Sunday Min temperature: 17.96°C Max temperature: 23.31°C Summary: Mostly cloudy throughout the day.
Lovely, that is what I wanted. We have used around 30 lines to write a weather forecast tool, you can modify it to make your own weather tool.
What we have learnt
Of course, we have learnt the usage of the Dark Sky API. Other than that, you may notice we have used the Software Development Life Cycle (SDLC) phases as well. Firstly, we define a problem to solve (planning), then think about inputs and outputs (design), code a program (Implementation), have a test run (testing) and launch our software here (deployment). You can see, SDLC is nothing special, it can be applied to our daily experience.
Coding is, just a part of our life.
The complete source code can be found at https://github.com/codeastar/weather_on_trip .