Skip to content

Instantly share code, notes, and snippets.

@jasonsnell
Last active June 25, 2024 00:07
Show Gist options
  • Save jasonsnell/2757e58081a1ae377a9c0feed875976b to your computer and use it in GitHub Desktop.
Save jasonsnell/2757e58081a1ae377a9c0feed875976b to your computer and use it in GitHub Desktop.
WeatherKit API sample
#! /usr/bin/env python3
import time
import jwt
import json
import requests
from datetime import datetime
from collections import defaultdict
import matplotlib.pyplot as plt
theDayCondition = defaultdict(lambda: -99999)
hitemp = defaultdict(lambda: -99999)
lotemp = defaultdict(lambda: 99999)
datelist = defaultdict(lambda: 99999)
diff = {}
theDates = [1, 2, 3, 4, 5, 6, 7, 8]
# all these variables below need to be customized
lat = "your-latitude"
lon = "your-longitude"
chartSavePath = '/Users/your-user-name/Desktop/'
team_id = "your_team_id"
service_id = "com.yourdomain.weatherproject"
key_id = "your_key_id"
private_key = "-----YOUR PRIVATE KEY-----"
def symbolFromConditions(theCondition, theRequest):
# SFSymbols look weird but they theoretically will print properly!
conditionSymbol = ""
if theCondition == "Clear":
symbolName = "sun.max"
theSFSymbol = "􀆭"
elif theCondition == "MostlyClear":
symbolName = "sun.min"
theSFSymbol = "􀆫"
elif theCondition == "PartlyCloudy":
symbolName = "cloud.sun"
theSFSymbol = "􀇔"
elif theCondition == "MostlyCloudy":
symbolName = "cloud"
theSFSymbol = "􀇂"
elif theCondition == "Cloudy":
symbolName = "cloud"
theSFSymbol = "􀇂"
elif theCondition == "Hazy":
symbolName = "sun.haze"
theSFSymbol = "􀆷"
elif theCondition == "ScatteredThunderstorms":
symbolName = "cloud.sun.bolt"
theSFSymbol = "􀇘"
elif theCondition == "Drizzle":
symbolName = "cloud.drizzle"
theSFSymbol = "􀇄"
elif theCondition == "rain":
symbolName = "cloud.rain"
theSFSymbol = "􀇆"
elif theCondition == "HeavyRain":
symbolName = "cloud.heavyrain"
theSFSymbol = "􀇈"
else:
symbolName = theCondition
theSFSymbol = theCondition
if theRequest == "sf":
return theSFSymbol
else:
return (f':{symbolName}: ')
expiry = (int(time.time()) + 60)
encoded_jwt = jwt.encode({"iss": team_id, "iat": int(time.time()), "exp": expiry, "sub": service_id}, private_key, algorithm="ES256", headers={"kid": key_id, "id": (team_id + '.' + service_id)})
dailyurl = f"https://weatherkit.apple.com/api/v1/weather/en/{lat}/{lon}?dataSets=forecastDaily&timezone=America/Los_Angeles"
d = requests.get(dailyurl, headers={"Authorization":("Bearer " + encoded_jwt)})
if len(d.content) < 1:
raise Exception("File not retrieved")
# dailyForecast is the variable containing the entire forecast payload
dailyForecast = json.loads(d.content)
todayHiC = dailyForecast['forecastDaily']['days'][0]['temperatureMax']
todayLoC = dailyForecast['forecastDaily']['days'][0]['temperatureMin']
todayHiF = int((todayHiC * 9/5) + 32)
todayLoF = int((todayLoC * 9/5) + 32)
todayCondition = dailyForecast['forecastDaily']['days'][0]['restOfDayForecast']['conditionCode']
todayPrecip = dailyForecast['forecastDaily']['days'][0]['restOfDayForecast']['precipitationType']
if todayPrecip != "clear":
conditionSymbol = symbolFromConditions(todayPrecip, '')
else:
conditionSymbol = symbolFromConditions(todayCondition, '')
print (f'{conditionSymbol} {todayHiF}°/{todayLoF}°')
for dayItem in range(1,9):
thisHiC = dailyForecast['forecastDaily']['days'][dayItem]['temperatureMax']
hitemp[dayItem] = int((thisHiC * 9/5) + 32)
theDay = dailyForecast['forecastDaily']['days'][dayItem]['forecastStart']
theDayProper = datetime.strptime(theDay, "%Y-%m-%dT%H:%M:%SZ")
datelist[dayItem] = datetime.strftime(theDayProper, "%a")
theDayCondition[dayItem] = dailyForecast['forecastDaily']['days'][dayItem]['conditionCode']
thatPrecip = dailyForecast['forecastDaily']['days'][dayItem]['precipitationType']
# print(thatPrecip)
if thatPrecip != "clear":
theDayCondition[dayItem] = symbolFromConditions(thatPrecip, 'sf')
else:
theDayCondition[dayItem] = symbolFromConditions(theDayCondition[dayItem], 'sf')
theHighs = list(hitemp.values())
theDateList = list(datelist.values())
theConditionsList = list(theDayCondition.values())
himin = min(theHighs) - 8
# Graphing
fig, ax = plt.subplots()
font = {'fontname': 'SF Pro'}
ax.bar(theDates, theHighs, color="#333", alpha=0)
ax.bar_label(ax.containers[0], color="black", fontweight='bold')
ax.set_aspect(aspect=0.12)
ax.set_yticks([])
for i in range(0,8):
plt.text((i+1),(himin + 2),str(theConditionsList[i]), color="black", horizontalalignment='center', size='x-large', fontweight='bold', **font)
plt.box(False)
plt.ylim(ymin=himin)
plt.xticks(theDates, theDateList, color="black", fontweight='bold')
plt.savefig(f'{chartSavePath}forecast.png', dpi=300, bbox_inches='tight',
pad_inches=0.05)
@RGSMA
Copy link

RGSMA commented Jul 19, 2022

I'm very new to WeatherKit and trying to use your example script as a start to replace my DarkSky script that runs headless on a RaspberryPi. I'm simply trying to get the UV index for my lat/lon

It seems that installing the jwt library is the problem. Any suggestions or help would be appreciated. Thanks Jason

@jasonsnell
Copy link
Author

I am not a python expert but "pip install pyjwt" or "pip3 install pyjwt" to install that module

@RGSMA
Copy link

RGSMA commented Jul 20, 2022

Thanks Jason. I was able to figure out the error; I needed to load the private_key as a file -NOT- embed the key in my code. The original Python script that you wrote was extremely helpful for my project as I move on from DarkSky to WeatherKit. I now need to polish my Python script a little but at least I have it working. Thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment