Update inkycal_weather.py

This commit is contained in:
Ace 2019-11-05 15:45:56 +01:00 committed by GitHub
parent e3a4997fdb
commit 8a53438191
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -3,8 +3,10 @@
""" """
Weather module for Inky-Calendar software. In development... Weather module for Inky-Calendar software. In development...
To-do: The lunar phase calculation algorithm was taken from Michael Bishop
- make locations of icons and text dynamic from Github after being granted permission. Thanks, Michael Bishop for your
awesome code!
Copyright by aceisace Copyright by aceisace
""" """
from __future__ import print_function from __future__ import print_function
@ -13,6 +15,8 @@ from settings import *
from configuration import * from configuration import *
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
import arrow import arrow
import math, decimal
dec = decimal.Decimal
print('Initialising weather...', end=' ') print('Initialising weather...', end=' ')
owm = pyowm.OWM(api_key, language=language) owm = pyowm.OWM(api_key, language=language)
@ -29,122 +33,248 @@ weathericons = {
} }
"""Split top_section into to 2 rows""" """Add a border to increase readability"""
section_height = top_section_height // 2 border_top = int(top_section_height * 0.05)
section_width = (top_section_width - top_section_height) // 3 border_left = int(top_section_width * 0.02)
"""Allocate icon sizes""" """Calculate size for each weather sub-section"""
icon_small = section_height row_height = (top_section_height-(border_top*2)) // 3
icon_large = top_section_height coloumn_width = (top_section_width-(border_left*2)) // 7
"""Split top section into 4 coloums""" """Calculate paddings"""
section1 = 0 x_padding = int( (top_section_width % coloumn_width) / 2 )
section2 = icon_large + (top_section_width - icon_large) // 3 * 0 y_padding = int( (top_section_height % row_height) / 2 )
section3 = icon_large + (top_section_width - icon_large) // 3 * 1
section4 = icon_large + (top_section_width - icon_large) // 3 * 2
"""Allocate positions for icons""" """Allocate sizes for weather icons"""
weather_icon_pos = (section1, 0) icon_small = row_height
wind_icon_pos = (section2, 0) icon_medium = row_height * 2
sun_icon_pos = (section3, 0)
temperature_icon_pos = (section4, 0)
weather_description_pos = (section2, section_height)
humidity_icon_pos = (section4, section_height)
"""Allocate positions for text""" """Calculate the x-axis position of each coloumn"""
next_to = lambda x: (x[0]+ icon_small, x[1]) coloumn1 = x_padding
icon_offset = section_width - icon_small coloumn2 = coloumn1 + coloumn_width
coloumn3 = coloumn2 + coloumn_width
coloumn4 = coloumn3 + coloumn_width
coloumn5 = coloumn4 + coloumn_width
coloumn6 = coloumn5 + coloumn_width
coloumn7 = coloumn6 + coloumn_width
wind_pos = next_to(wind_icon_pos) """Calculate the y-axis position of each row"""
temperature_pos = next_to(temperature_icon_pos) row1 = y_padding
sun_pos = next_to(sun_icon_pos) row2 = row1 + row_height
humidity_pos = next_to(humidity_icon_pos) row3 = row2 + row_height
weather_pos = (section2, section_height)
"""Allocate positions for current weather details"""
text_now_pos = (coloumn1, row1)
weather_icon_now_pos = (coloumn1, row2)
temperature_icon_now_pos = (coloumn2, row1)
temperature_now_pos = (coloumn2+icon_small, row1)
humidity_icon_now_pos = (coloumn2, row2)
humidity_now_pos = (coloumn2+icon_small, row2)
windspeed_icon_now_pos = (coloumn2, row3)
windspeed_now_pos = (coloumn2+icon_small, row3)
moon_phase_now_pos = (coloumn3, row1)
sunrise_icon_now_pos = (coloumn3, row2)
sunrise_time_now_pos = (coloumn3+icon_small, row2)
sunset_icon_now_pos = (coloumn3, row3)
sunset_time_now_pos = (coloumn3+ icon_small, row3)
"""Allocate positions for weather forecast after 3 hours"""
text_3h_pos = (coloumn4, row1)
icon_3h_pos = (coloumn4, row2)
temperature_3h_pos = (coloumn4, row3)
"""Allocate positions for weather forecast after 6 hours"""
text_6h_pos = (coloumn5, row1)
icon_6h_pos = (coloumn5, row2)
temperature_6h_pos = (coloumn5, row3)
"""Allocate positions for weather forecast after 9 hours"""
text_9h_pos = (coloumn6, row1)
icon_9h_pos = (coloumn6, row2)
temperature_9h_pos = (coloumn6, row3)
"""Allocate positions for weather forecast after 12 hours"""
text_12h_pos = (coloumn7, row1)
icon_12h_pos = (coloumn7, row2)
temperature_12h_pos = (coloumn7, row3)
"""Windspeed (m/s) to beaufort (index of list) conversion"""
windspeed_to_beaufort = [0.02, 1.5, 3.3, 5.4, 7.9, 10.7, 13.8, 17.1, 20.7,
24.4, 28.4, 32.6, 100]
"""Function to convert tempertures from kelvin to celcius or fahrenheit"""
def to_units(kelvin):
if units == 'metric':
conversion = str(int(kelvin - 273.15)) + '°C'
else:
conversion = str(int((kelvin - 273.15) * 9/5 + 32)) + 'F'
return conversion
"""Function to convert time objects to specified format 12/24 hours"""
"""Simple means just the hour and if 12 hours, am/pm as well"""
def to_hours(datetime_object, simple = False):
if hours == '24':
if simple == True:
converted_time = datetime_object.format('H')
else:
converted_time = datetime_object.format('HH:mm')
else:
if simple == True:
converted_time = datetime_object.format('H a')
else:
converted_time = datetime_object.format('hh:mm')
return str(converted_time)
#def main(): #def main():
try:
"""Connect to Openweathermap API and fetch weather data""" """Connect to Openweathermap API and fetch weather data"""
if top_section == "Weather" and api_key != "" and owm.is_API_online() is True: if top_section == "Weather" and api_key != "" and owm.is_API_online() is True:
try: #try:
print("Fetching weather data from openweathermap...",end = ' ') print("Fetching weather data from openweathermap API...",end = ' ')
observation = owm.weather_at_place(location) current_weather_setup = owm.weather_at_place(location)
weather = current_weather_setup.get_weather()
"""Set-up and get weather forecast data"""
forecast = owm.three_hours_forecast(location)
print("Done") print("Done")
weather = observation.get_weather() """Round the hour to the nearest multiple of 3"""
weathericon = weather.get_weather_icon_name()
Humidity = str(weather.get_humidity())
cloudstatus = str(weather.get_clouds())
weather_description = (str(weather.get_detailed_status()))
"""Add the icons at the correct positions"""
print('Adding weather info and icons to the image...', end = ' ')
write_text(icon_small, icon_small, '\uf055', temperature_icon_pos,
font = w_font, adapt_fontsize = True) # Temperature icon
write_text(icon_large, icon_large, weathericons[weathericon],
weather_icon_pos, font = w_font, adapt_fontsize = True) # Weather icon
write_text(icon_small, icon_small, '\uf07a', humidity_icon_pos, font = w_font,
adapt_fontsize = True) #Humidity icon
write_text(icon_small,icon_small, '\uf050', wind_icon_pos, font = w_font,
adapt_fontsize = True) #Wind icon
"""Format and write the temperature and windspeed"""
if units == "metric":
Temperature = str(int(weather.get_temperature(unit='celsius')['temp']))
windspeed = str(int(weather.get_wind()['speed']))
write_text(icon_offset, section_height, Temperature+'°C', temperature_pos)
write_text(icon_offset,section_height, windspeed+" km/h", wind_pos)
else:
Temperature = str(int(weather.get_temperature('fahrenheit')['temp']))
windspeed = str(int(weather.get_wind()['speed']*0.621))
write_text(icon_offset, section_height, Temperature+' F', temperature_pos)
write_text(icon_offset,section_height, windspeed+" mph", wind_pos)
"""write the humidity at the given position"""
write_text(icon_offset, section_height, Humidity+'%', humidity_pos)
now = arrow.now(tz=get_tz()) now = arrow.now(tz=get_tz())
sunrise = arrow.get(weather.get_sunrise_time()).to(get_tz()) hour_gap = (now.hour % 3)
sunset = arrow.get(weather.get_sunset_time()).to(get_tz())
"""Add the sunrise/sunset icon and display the time""" """Prepare timings for forecasts"""
if (now <= sunrise and now <= sunset) or (now >= sunrise and now >= sunset): in_3h = now.replace(hours = + hour_gap + 3)
write_text(icon_small, icon_small, '\uf051', sun_icon_pos, font = w_font, in_6h = now.replace(hours = + hour_gap + 6)
adapt_fontsize = True) in_9h = now.replace(hours = + hour_gap + 9)
if hours == "24": in_12h = now.replace(hours = + hour_gap + 12)
write_text(icon_offset, section_height, sunrise.format('H:mm'), sun_pos)
else: """Prepare forecast objects for the specified timings"""
write_text(icon_offset, section_height, sunrise.format('h:mm'), sun_pos) forecast_3h = forecast.get_weather_at(in_3h.datetime)
else: forecast_6h = forecast.get_weather_at(in_6h.datetime)
write_text(icon_small, '\uf052', sun_icon_pos, font = w_font, forecast_9h = forecast.get_weather_at(in_9h.datetime)
adapt_fontsize = True) forecast_12h = forecast.get_weather_at(in_12h.datetime)
if hours == "24":
write_text(icon_offset, section_height, sunset.format('H:mm'), sun_pos) """Get the current temperature and forcasts temperatures"""
else: temperature_now = to_units(weather.get_temperature()['temp'])
write_text(icon_offset, section_height, sunset.format('h:mm'), sun_pos) temperature_3h = to_units(forecast_3h.get_temperature()['temp'])
temperature_6h = to_units(forecast_6h.get_temperature()['temp'])
temperature_9h = to_units(forecast_9h.get_temperature()['temp'])
temperature_12h = to_units(forecast_12h.get_temperature()['temp'])
"""Get current and forecast weather icon names"""
weather_icon_now = weather.get_weather_icon_name()
weather_icon_3h = forecast_3h.get_weather_icon_name()
weather_icon_6h = forecast_6h.get_weather_icon_name()
weather_icon_9h = forecast_9h.get_weather_icon_name()
weather_icon_12h = forecast_12h.get_weather_icon_name()
"""Parse current weather details"""
sunrise_time_now = arrow.get(weather.get_sunrise_time()).to(get_tz())
sunset_time_now = arrow.get(weather.get_sunset_time()).to(get_tz())
humidity_now = str(weather.get_humidity())
cloudstatus_now = str(weather.get_clouds())
weather_description_now = str(weather.get_detailed_status())
windspeed_now = weather.get_wind(unit='meters_sec')['speed']
beaufort = str([windspeed_to_beaufort.index(_) for _ in windspeed_to_beaufort
if windspeed_now < _][0])
"""Add a short weather description""" """Calculate the moon phase"""
write_text(section2+section3-icon_offset, section_height, def get_moon_phase():
weather_description, weather_pos) diff = now - arrow.get(2001, 1, 1)
days = dec(diff.days) + (dec(diff.seconds) / dec(86400))
lunations = dec("0.20439731") + (days * dec("0.03386319269"))
position = lunations % dec(1)
index = math.floor((position * dec(8)) + dec("0.5"))
return {0: '\uf095',1: '\uf099',2: '\uf09c',3: '\uf0a0',
4: '\uf0a3',5: '\uf0a7',6: '\uf0aa',7: '\uf0ae' }[int(index) & 7]
moonphase = get_moon_phase()
print('Adding weather details on the image...', end = ' ')
"""Add weather details in column 1"""
write_text(coloumn_width, row_height, 'now', text_now_pos)
write_text(icon_medium, icon_medium, weathericons[weather_icon_now],
weather_icon_now_pos, font = w_font, adapt_fontsize = True)
"""Add weather details in column 2"""
write_text(icon_small, icon_small, '\uf053', temperature_icon_now_pos,
font = w_font, adapt_fontsize = True)
write_text(icon_small, icon_small, '\uf07a', humidity_icon_now_pos,
font = w_font, adapt_fontsize = True)
write_text(icon_small, icon_small, '\uf050', windspeed_icon_now_pos,
font = w_font, adapt_fontsize = True)
write_text(coloumn_width-icon_small, row_height,
temperature_now, temperature_now_pos)
write_text(coloumn_width-icon_small, row_height, humidity_now+'%',
humidity_now_pos)
write_text(coloumn_width-icon_small, row_height, beaufort,
windspeed_now_pos)
"""Add weather details in column 3"""
write_text(coloumn_width, row_height, moonphase , moon_phase_now_pos,
font = w_font, adapt_fontsize = True)
write_text(icon_small, icon_small, '\uf051', sunrise_icon_now_pos,
font = w_font, adapt_fontsize = True)
write_text(icon_small, icon_small, '\uf052', sunset_icon_now_pos,
font = w_font, adapt_fontsize = True)
write_text(coloumn_width-icon_small, row_height, to_hours(sunrise_time_now),
sunrise_time_now_pos)
write_text(coloumn_width-icon_small, row_height, to_hours(sunset_time_now),
sunset_time_now_pos)
"""Add weather details in column 4"""
write_text(coloumn_width, row_height, to_hours(in_3h, simple=True),
text_3h_pos)
write_text(coloumn_width, row_height, weathericons[weather_icon_3h],
icon_3h_pos, font = w_font, adapt_fontsize = True)
write_text(coloumn_width, row_height, temperature_3h,
temperature_3h_pos)
"""Add weather details in column 5"""
write_text(coloumn_width, row_height, to_hours(in_6h, simple=True),
text_6h_pos)
write_text(coloumn_width, row_height, weathericons[weather_icon_6h],
icon_6h_pos, font = w_font, adapt_fontsize = True)
write_text(coloumn_width, row_height, temperature_6h,
temperature_6h_pos)
"""Add weather details in column 6"""
write_text(coloumn_width, row_height, to_hours(in_9h, simple=True),
text_9h_pos)
write_text(coloumn_width, row_height, weathericons[weather_icon_9h],
icon_9h_pos, font = w_font, adapt_fontsize = True)
write_text(coloumn_width, row_height, temperature_9h,
temperature_9h_pos)
"""Add weather details in column 7"""
write_text(coloumn_width, row_height, to_hours(in_12h, simple=True),
text_12h_pos)
write_text(coloumn_width, row_height, weathericons[weather_icon_12h],
icon_12h_pos, font = w_font, adapt_fontsize = True)
write_text(coloumn_width, row_height, temperature_12h,
temperature_12h_pos)
"""Add seperators between section4 and section7"""
draw = ImageDraw.Draw(image)
line_start_y = int(top_section_height*0.1)
line_end_y = int(top_section_height*0.9)
draw.line((coloumn4, line_start_y, coloumn4, line_end_y), fill='black')
draw.line((coloumn5, line_start_y, coloumn5, line_end_y), fill='black')
draw.line((coloumn6, line_start_y, coloumn6, line_end_y), fill='black')
draw.line((coloumn7, line_start_y, coloumn7, line_end_y), fill='black')
draw.line((0, top_section_height-border_top, top_section_width-border_left,
top_section_height-border_top), fill='red', width=3)
print('Done'+'\n') print('Done'+'\n')
"""Show the fetched weather data"""
print("Today's weather report: The current Temperature is {0}°C. The "
"relative humidity is {1} %. The current windspeed is {2} km/h. "
"The sunrise today was at {3}. The sunset is at {4}. The weather can "
"be described with: {5}".format(Temperature, Humidity, windspeed,
sunrise.format('H:mm'), sunset.format('H:mm'), weather_description))
image.crop((0,0, top_section_width, top_section_height)).save('weather.png') image.crop((0,0, top_section_width, top_section_height)).save('weather.png')
except Exception as e: except Exception as e:
@ -152,8 +282,10 @@ if top_section == "Weather" and api_key != "" and owm.is_API_online() is True:
api server, add the cloud with question mark""" api server, add the cloud with question mark"""
print('__________OWM-ERROR!__________') print('__________OWM-ERROR!__________')
print('Reason: ',e) print('Reason: ',e)
write_text(icon_large, icon_large, '\uf07b', weather_icon_pos, write_text(icon_medium, icon_medium, '\uf07b', weather_icon_now_pos,
font = w_font, adapt_fontsize = True) font = w_font, adapt_fontsize = True)
message = 'No internet connectivity or API timeout'
write_text(coloumn_width*6, row_height, message, humidity_icon_now_pos)
pass pass