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,132 +33,260 @@ 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"""
if top_section == "Weather" and api_key != "" and owm.is_API_online() is True:
#try:
print("Fetching weather data from openweathermap API...",end = ' ')
current_weather_setup = owm.weather_at_place(location)
weather = current_weather_setup.get_weather()
"""Connect to Openweathermap API and fetch weather data""" """Set-up and get weather forecast data"""
if top_section == "Weather" and api_key != "" and owm.is_API_online() is True: forecast = owm.three_hours_forecast(location)
try:
print("Fetching weather data from openweathermap...",end = ' ')
observation = owm.weather_at_place(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:
"""If no response was received from the openweathermap """If no response was received from the openweathermap
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)
pass message = 'No internet connectivity or API timeout'
write_text(coloumn_width*6, row_height, message, humidity_icon_now_pos)
pass
#if __name__ == '__main__': #if __name__ == '__main__':