I’m spending waaaay too much time in terminal these days and I’m slowly replacing functions I use on my Google Home Mini with commands on my MacBook, because, as always, why not?
The title says it all. I can now run a
So where to begin on this one. First of all, I needed to find a free weather API provider. Easy stuff, thanks Google. OpenWeather provide just that. Of course there are limited API requests, but I don’t think i will be exceeding those any time soon. From there on, it’s just as easy as sending a GET request to fetch some JSON and then parsing it to be displayed how I see fit.
The only technicality involved was converting a wind direction from degrees to an actual direction. But a spot of math and a big List later, simple.
So let’s get started. First of all, I had to make an account on https://openweathermap.org which is so self-explanatory I won’t even entertain explaining it. It takes a few hours for your API key to become active though, I kinda forgot until the evening so I don’t know exactly how long it takes.
Once thats done, take a look at their API documentation to see what kind of requests you can make. I just went with the first one, get current data by city name.
What the documentation doesn’t say for whatever strange reason is that you need to include your API key as a parameter with the name
So let’s get to writing some python code. I’ll be using the
I honestly can’t remember if
#! /usr/bin/python
import json
import requests
import sys
# api-endpoint
URL = "http://api.openweathermap.org/data/2.5/weather"
location = "city_here";
api_key = "api_key_here"
units = "metric" # metric for celsius, imperial for fahrenheit, no param for kelvin
temp_unit = "celsius" # descriptor for string
PARAMS = {'q': location, 'appid': api_key, 'units': units}
# using the requests library, we make a get request with the given URL and PARAMS
r = requests.get(url=URL, params=PARAMS)
# the json response is stored here
data = r.json()
direction_list = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW", "N"]
# is json key present
def ijkp(json, key):
try:
buf = json[key]
except KeyError:
return False
return True
# the JSON structure can be found at https://openweathermap.org/current
# set up some vars to contain the data I want to show
if ijkp(data, "main") == False:
print("Critical data missing. Terminating gracefully")
sys.exit()
if ijkp(data, "weather") == False:
print("Critical data missing. Terminating gracefully")
sys.exit()
if ijkp(data, "wind") == False:
print("Critical data missing. Terminating gracefully")
sys.exit()
temp = int(data['main']['temp']) if ijkp(data['main'], "temp") else int(-9999)
feels_like = int(data['main']['feels_like']) if ijkp(data['main'], "feels_like") else None
temp_low = int(data['main']['temp_min']) if ijkp(data['main'], "temp_min") else None
temp_high = int(data['main']['temp_max']) if ijkp(data['main'], "temp_max") else None
humidity = int(data['main']['humidity']) if ijkp(data['main'], "humidity") else None
weather_main = data['weather'][0]['main'] if ijkp(data['weather'][0], "main") else None
weather_desc = data['weather'][0]['description'] if ijkp(data['weather'][0], "description") else None
wind_speed = data['wind']['speed'] if ijkp(data['wind'], "speed") else None
wind_speed_mph = int(wind_speed * 2.237)
# calculate wind direction from degrees
dir_index = int(int(data['wind']['deg']) / 22.5) if ijkp(data['wind'], "deg") else None
wind_dir = direction_list[dir_index]
print("The current temperature in %s is %i degrees %s but it feels like %s degrees %s" % (
location, temp, temp_unit, feels_like, temp_unit))
print("The weather is mostly %s: %s" % (weather_main, weather_desc))
print("There is a %imph wind in a %s direction" % (wind_speed_mph, wind_dir))
print("The current humidity is %i%%" % (humidity))
So the code is a bit rough. It’s a hackjob. I might tidy it up in the future to traverse the JSON and only extract values if they are there and only display them if they are there, but for now, this does what I want. It crashed when I ran it a minute ago because
def ijkp(json, key):
try:
buf = json[key]
except KeyError:
return False
return True
This function’s sole purpose is to return false if a key doesn’t exist, and true otherwise. I use it in every variable declaration that relies on fetching information from the JSON, to ensure the program doesn’t crash. There are also several if-statements to ensure the core data is present in the JSON data and the program will terminate if it is missing.
In order to calculate the wind direction from meteorological degrees, I take a List containing all the possible directions:
direction_list = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW", "N"]
North is at both the start and end because both 0 and 360 degrees can represent north, so there are 16 unique elements in this List.
360 / 16 = 22.5
360 degrees divided by 16 unique possibilities = 22.5
So I fetch the wind direction in degrees and then divide that by 22.5. The wind direction is explicitly converted to an int just to ensure it remains a whole number. As is the result of the next calculation, to force round the number. Let’s assume the degrees value is 180, a South direction.
180 / 22.5 = 8.
and thus we fetch the value at the 8th index of the list, which is “S”.
Finally, as always, I move this script to my
Although I simply threw this code together quickly, the functionality I sought is there, and the real reason behind it is because I’ve been neglecting Python for too long. All the years I’ve been writing code, I’ve barely touched this language. Because I started with PHP and then C++, I am very comfortable with a C-style syntax, so when indentation and colons become the norm, its very foreign to me. So, the more I write, the more comfortable I get. And that, ladies and gentlemen, is why this script now exists on my laptop!