diff --git a/inkycal/custom/__init__.py b/inkycal/custom/__init__.py index b4471713..f9d1efb1 100644 --- a/inkycal/custom/__init__.py +++ b/inkycal/custom/__init__.py @@ -1,2 +1,3 @@ from .functions import * from .inkycal_exceptions import * +from .openweathermap_wrapper import OpenWeatherMap \ No newline at end of file diff --git a/inkycal/custom/functions.py b/inkycal/custom/functions.py index 2a588f8c..046e8fd5 100644 --- a/inkycal/custom/functions.py +++ b/inkycal/custom/functions.py @@ -6,8 +6,10 @@ Copyright by aceinnolab """ import logging +import traceback + from PIL import Image, ImageDraw, ImageFont, ImageColor -from urllib.request import urlopen +import requests import os import time @@ -98,11 +100,13 @@ def auto_fontsize(font, max_height): Returns: A PIL font object with modified height. """ - - fontsize = font.getsize('hg')[1] - while font.getsize('hg')[1] <= (max_height * 0.80): + text_bbox = font.getbbox("hg") + text_height = text_bbox[3] - text_bbox[1] + fontsize = text_height + while text_height <= (max_height * 0.80): fontsize += 1 font = ImageFont.truetype(font.path, fontsize) + text_height = text_bbox[3] - text_bbox[1] return font @@ -154,21 +158,34 @@ def write(image, xy, box_size, text, font=None, **kwargs): if autofit or (fill_width != 1.0) or (fill_height != 0.8): size = 8 font = ImageFont.truetype(font.path, size) - text_width, text_height = font.getsize(text)[0], font.getsize('hg')[1] + text_bbox = font.getbbox(text) + text_width = text_bbox[2] - text_bbox[0] + text_bbox_height = font.getbbox("hg") + text_height = text_bbox_height[3] - text_bbox_height[1] + while (text_width < int(box_width * fill_width) and text_height < int(box_height * fill_height)): size += 1 font = ImageFont.truetype(font.path, size) - text_width, text_height = font.getsize(text)[0], font.getsize('hg')[1] + text_bbox = font.getbbox(text) + text_width = text_bbox[2] - text_bbox[0] + text_bbox_height = font.getbbox("hg") + text_height = text_bbox_height[3] - text_bbox_height[1] - text_width, text_height = font.getsize(text)[0], font.getsize('hg')[1] + text_bbox = font.getbbox(text) + text_width = text_bbox[2] - text_bbox[0] + text_bbox_height = font.getbbox("hg") + text_height = text_bbox_height[3] - text_bbox_height[1] # Truncate text if text is too long so it can fit inside the box if (text_width, text_height) > (box_width, box_height): logs.debug(('truncating {}'.format(text))) while (text_width, text_height) > (box_width, box_height): text = text[0:-1] - text_width, text_height = font.getsize(text)[0], font.getsize('hg')[1] + text_bbox = font.getbbox(text) + text_width = text_bbox[2] - text_bbox[0] + text_bbox_height = font.getbbox("hg") + text_height = text_bbox_height[3] - text_bbox_height[1] logs.debug(text) # Align text to desired position @@ -215,14 +232,17 @@ def text_wrap(text, font=None, max_width=None): A list containing chunked strings of the full text. """ lines = [] - if font.getsize(text)[0] < max_width: + + text_width = font.getlength(text) + + if text_width < max_width: lines.append(text) else: words = text.split(' ') i = 0 while i < len(words): line = '' - while i < len(words) and font.getsize(line + words[i])[0] <= max_width: + while i < len(words) and font.getlength(line + words[i]) <= max_width: line = line + words[i] + " " i += 1 if not line: @@ -249,9 +269,10 @@ def internet_available(): """ try: - urlopen('https://google.com', timeout=5) + requests.get('https://google.com', timeout=5) return True except: + print(f"Network could not be reached: {traceback.print_exc()}") return False diff --git a/inkycal/custom/openweathermap_wrapper.py b/inkycal/custom/openweathermap_wrapper.py new file mode 100644 index 00000000..20c050f7 --- /dev/null +++ b/inkycal/custom/openweathermap_wrapper.py @@ -0,0 +1,43 @@ +import logging +from enum import Enum + +import requests +import json + +logger = logging.getLogger(__name__) + +class WEATHER_OPTIONS(Enum): + CURRENT_WEATHER = "weather" + +class FORECAST_INTERVAL(Enum): + THREE_HOURS = "3h" + FIVE_DAYS = "5d" + + + +class OpenWeatherMap: + def __init__(self, api_key:str, city_id:int, units:str) -> None: + self.api_key = api_key + self.city_id = city_id + assert (units in ["metric", "imperial"] ) + self.units = units + self._api_version = "2.5" + self._base_url = f"https://api.openweathermap.org/data/{self._api_version}" + + + def get_current_weather(self) -> dict: + current_weather_url = f"{self._base_url}/weather?id={self.city_id}&appid={self.api_key}&units={self.units}" + response = requests.get(current_weather_url) + if not response.ok: + raise AssertionError(f"Failure getting the current weather: code {response.status_code}. Reason: {response.text}") + data = json.loads(response.text) + return data + + def get_weather_forecast(self) -> dict: + forecast_url = f"{self._base_url}/forecast?id={self.city_id}&appid={self.api_key}&units={self.units}" + response = requests.get(forecast_url) + if not response.ok: + raise AssertionError(f"Failure getting the current weather: code {response.status_code}. Reason: {response.text}") + data = json.loads(response.text)["list"] + return data + diff --git a/inkycal/modules/inkycal_agenda.py b/inkycal/modules/inkycal_agenda.py index f4ddbd6e..b5adbd2c 100755 --- a/inkycal/modules/inkycal_agenda.py +++ b/inkycal/modules/inkycal_agenda.py @@ -98,7 +98,9 @@ def generate_image(self): # Calculate the max number of lines that can fit on the image line_spacing = 1 - line_height = int(self.font.getsize('hg')[1]) + line_spacing + + text_bbox_height = self.font.getbbox("hg") + line_height = text_bbox_height[3] - text_bbox_height[1] + line_spacing line_width = im_width max_lines = im_height // line_height logger.debug(f'max lines: {max_lines}') @@ -133,8 +135,8 @@ def generate_image(self): # parser.show_events() # Set the width for date, time and event titles - date_width = int(max([self.font.getsize( - dates['begin'].format(self.date_format, locale=self.language))[0] + date_width = int(max([self.font.getlength( + dates['begin'].format(self.date_format, locale=self.language)) for dates in agenda_events]) * 1.2) logger.debug(f'date_width: {date_width}') @@ -147,8 +149,9 @@ def generate_image(self): logger.info('Managed to parse events from urls') # Find out how much space the event times take - time_width = int(max([self.font.getsize( - events['begin'].format(self.time_format, locale=self.language))[0] + + time_width = int(max([self.font.getlength( + events['begin'].format(self.time_format, locale=self.language)) for events in upcoming_events]) * 1.2) logger.debug(f'time_width: {time_width}') diff --git a/inkycal/modules/inkycal_calendar.py b/inkycal/modules/inkycal_calendar.py index c6dfea59..65012a18 100755 --- a/inkycal/modules/inkycal_calendar.py +++ b/inkycal/modules/inkycal_calendar.py @@ -110,7 +110,8 @@ def generate_image(self): # Allocate space for month-names, weekdays etc. month_name_height = int(im_height * 0.10) - weekdays_height = int(self.font.getsize('hg')[1] * 1.25) + text_bbox_height = self.font.getbbox("hg") + weekdays_height = int((text_bbox_height[3] - text_bbox_height[1])* 1.25) logger.debug(f"month_name_height: {month_name_height}") logger.debug(f"weekdays_height: {weekdays_height}") @@ -182,15 +183,15 @@ def generate_image(self): ] logger.debug(f'weekday names: {weekday_names}') - for idx, weekday in enumerate(weekday_pos): + for index, weekday in enumerate(weekday_pos): write( im_black, weekday, (icon_width, weekdays_height), - weekday_names[idx], + weekday_names[index], font=self.font, autofit=True, - fill_height=1.0, + fill_height=0.9, ) # Create a calendar template and flatten (remove nestings) @@ -207,6 +208,10 @@ def generate_image(self): # remove zeros from calendar since they are not required calendar_flat = [num for num in calendar_flat if num != 0] + # ensure all numbers have the same size + fontsize_numbers = int(min(icon_width, icon_height) * 0.5) + number_font = ImageFont.truetype(self.font.path, fontsize_numbers) + # Add the numbers on the correct positions for number in calendar_flat: if number != int(now.day): @@ -215,9 +220,7 @@ def generate_image(self): grid[number], (icon_width, icon_height), str(number), - font=self.num_font, - fill_height=0.5, - fill_width=0.5, + font=number_font, ) # Draw a red/black circle with the current day of month in white @@ -262,10 +265,10 @@ def generate_image(self): from inkycal.modules.ical_parser import iCalendar # find out how many lines can fit at max in the event section - line_spacing = 0 - max_event_lines = events_height // ( - self.font.getsize('hg')[1] + line_spacing - ) + line_spacing = 2 + text_bbox_height = self.font.getbbox("hg") + line_height = text_bbox_height[3] - text_bbox_height[1] + line_spacing + max_event_lines = events_height // (line_height + line_spacing) # generate list of coordinates for each line events_offset = im_height - events_height @@ -329,31 +332,18 @@ def generate_image(self): # Find out how much space (width) the date format requires lang = self.language - date_width = int( - max( - ( - self.font.getsize( - events['begin'].format(self.date_format, locale=lang) - )[0] - for events in upcoming_events - ) - ) - * 1.1 + date_width = int(max(( + self.font.getlength(events['begin'].format(self.date_format, locale=lang)) + for events in upcoming_events))* 1.1 ) - time_width = int( - max( - ( - self.font.getsize( - events['begin'].format(self.time_format, locale=lang) - )[0] - for events in upcoming_events - ) - ) - * 1.1 + time_width = int(max(( + self.font.getlength(events['begin'].format(self.time_format, locale=lang)) + for events in upcoming_events))* 1.1 ) - line_height = self.font.getsize('hg')[1] + line_spacing + text_bbox_height = self.font.getbbox("hg") + line_height = text_bbox_height[3] - text_bbox_height[1] + line_spacing event_width_s = im_width - date_width - time_width event_width_l = im_width - date_width @@ -411,12 +401,13 @@ def generate_image(self): cursor += 1 else: symbol = '- ' - while self.font.getsize(symbol)[0] < im_width * 0.9: + + while self.font.getlength(symbol) < im_width * 0.9: symbol += ' -' write( im_black, event_lines[0], - (im_width, self.font.getsize(symbol)[1]), + (im_width, line_height), symbol, font=self.font, ) diff --git a/inkycal/modules/inkycal_feeds.py b/inkycal/modules/inkycal_feeds.py index 3e3b0548..e354b892 100644 --- a/inkycal/modules/inkycal_feeds.py +++ b/inkycal/modules/inkycal_feeds.py @@ -91,9 +91,11 @@ def generate_image(self): # Set some parameters for formatting feeds line_spacing = 1 - line_height = self.font.getsize('hg')[1] + line_spacing + line_width = im_width - max_lines = (im_height // (self.font.getsize('hg')[1] + line_spacing)) + text_bbox_height = self.font.getbbox("hg") + line_height = text_bbox_height[3] - text_bbox_height[1] + line_spacing + max_lines = (im_height // (line_height + line_spacing)) # Calculate padding from top so the lines look centralised spacing_top = int(im_height % line_height / 2) diff --git a/inkycal/modules/inkycal_jokes.py b/inkycal/modules/inkycal_jokes.py index e7e1b399..deb4a418 100755 --- a/inkycal/modules/inkycal_jokes.py +++ b/inkycal/modules/inkycal_jokes.py @@ -54,10 +54,11 @@ def generate_image(self): raise NetworkNotReachableError # Set some parameters for formatting feeds - line_spacing = 1 - line_height = self.font.getsize('hg')[1] + line_spacing + line_spacing = 5 + text_bbox = self.font.getbbox("hg") + line_height = text_bbox[3] - text_bbox[1] + line_spacing line_width = im_width - max_lines = (im_height // (self.font.getsize('hg')[1] + line_spacing)) + max_lines = (im_height // (line_height + line_spacing)) logger.debug(f"max_lines: {max_lines}") diff --git a/inkycal/modules/inkycal_stocks.py b/inkycal/modules/inkycal_stocks.py index 39002b20..e91e9f0c 100755 --- a/inkycal/modules/inkycal_stocks.py +++ b/inkycal/modules/inkycal_stocks.py @@ -96,9 +96,10 @@ def generate_image(self): # Set some parameters for formatting feeds line_spacing = 1 - line_height = self.font.getsize('hg')[1] + line_spacing + text_bbox_height = self.font.getbbox("hg") + line_height = text_bbox_height[3] - text_bbox_height[1] + line_spacing line_width = im_width - max_lines = (im_height // (self.font.getsize('hg')[1] + line_spacing)) + max_lines = (im_height // line_height) logger.debug(f"max_lines: {max_lines}") diff --git a/inkycal/modules/inkycal_textfile_to_display.py b/inkycal/modules/inkycal_textfile_to_display.py index cf3eb4d4..3d4617e5 100644 --- a/inkycal/modules/inkycal_textfile_to_display.py +++ b/inkycal/modules/inkycal_textfile_to_display.py @@ -7,11 +7,11 @@ Copyright by aceinnolab """ -from inkycal.modules.template import inkycal_module -from inkycal.custom import * - from urllib.request import urlopen +from inkycal.custom import * +from inkycal.modules.template import inkycal_module + logger = logging.getLogger(__name__) @@ -44,7 +44,6 @@ def __init__(self, config): self.make_request = True if self.filepath.startswith("https://") else False - # give an OK message print(f'{__name__} loaded') @@ -73,10 +72,11 @@ def generate_image(self): raise NetworkNotReachableError # Set some parameters for formatting feeds - line_spacing = 1 - line_height = self.font.getsize('hg')[1] + line_spacing + line_spacing = 4 + text_bbox_height = self.font.getbbox("hg") + line_height = text_bbox_height[3] - text_bbox_height[1] + line_spacing line_width = im_width - max_lines = (im_height // (self.font.getsize('hg')[1] + line_spacing)) + max_lines = im_height // line_height # Calculate padding from top so the lines look centralised spacing_top = int(im_height % line_height / 2) diff --git a/inkycal/modules/inkycal_todoist.py b/inkycal/modules/inkycal_todoist.py index 1995d9be..f2902536 100644 --- a/inkycal/modules/inkycal_todoist.py +++ b/inkycal/modules/inkycal_todoist.py @@ -86,9 +86,10 @@ def generate_image(self): # Set some parameters for formatting todos line_spacing = 1 - line_height = self.font.getsize('hg')[1] + line_spacing + text_bbox_height = self.font.getbbox("hg") + line_height = text_bbox_height[3] - text_bbox_height[1] + line_spacing line_width = im_width - max_lines = (im_height // (self.font.getsize('hg')[1] + line_spacing)) + max_lines = im_height // line_height # Calculate padding from top so the lines look centralised spacing_top = int(im_height % line_height / 2) diff --git a/inkycal/modules/inkycal_weather.py b/inkycal/modules/inkycal_weather.py index ec639bfa..cbb2cc8a 100644 --- a/inkycal/modules/inkycal_weather.py +++ b/inkycal/modules/inkycal_weather.py @@ -12,7 +12,7 @@ import decimal import arrow -from pyowm.owm import OWM +from inkycal.custom import OpenWeatherMap logger = logging.getLogger(__name__) @@ -95,7 +95,7 @@ def __init__(self, config): self.use_beaufort = config['use_beaufort'] # additional configuration - self.owm = OWM(self.api_key).weather_manager() + self.owm = OpenWeatherMap(api_key=self.api_key, city_id=self.location, units=config['units']) self.timezone = get_system_tz() self.locale = config['language'] self.weatherfont = ImageFont.truetype( @@ -104,6 +104,42 @@ def __init__(self, config): # give an OK message print(f"{__name__} loaded") + + @staticmethod + def mps_to_beaufort(meters_per_second:float) -> int: + """Map meters per second to the beaufort scale. + + Args: + meters_per_second: + float representing meters per seconds + + Returns: + an integer of the beaufort scale mapping the input + """ + thresholds = [0.3, 1.6, 3.4, 5.5, 8.0, 10.8, 13.9, 17.2, 20.7, 24.5, 28.4] + return next((i for i, threshold in enumerate(thresholds) if meters_per_second < threshold), 11) + + @staticmethod + def mps_to_mph(meters_per_second:float) -> float: + """Map meters per second to miles per hour, rounded to one decimal place. + + Args: + meters_per_second: + float representing meters per seconds. + + Returns: + float representing the input value in miles per hour. + """ + # 1 m/s is approximately equal to 2.23694 mph + miles_per_hour = meters_per_second * 2.23694 + return round(miles_per_hour, 1) + + @staticmethod + def celsius_to_fahrenheit(celsius:int or float): + """Converts the given temperate from degrees Celsius to Fahrenheit.""" + fahrenheit = (celsius * 9 / 5) + 32 + return fahrenheit + def generate_image(self): """Generate image for this module""" @@ -124,7 +160,11 @@ def generate_image(self): raise NetworkNotReachableError def get_moon_phase(): - """Calculate the current (approximate) moon phase""" + """Calculate the current (approximate) moon phase + + Returns: + The corresponding moonphase-icon. + """ dec = decimal.Decimal diff = now - arrow.get(2001, 1, 1) @@ -154,7 +194,7 @@ def is_negative(temp): return answer # Lookup-table for weather icons and weather codes - weathericons = { + weather_icons = { '01d': '\uf00d', '02d': '\uf002', '03d': '\uf013', @@ -227,26 +267,26 @@ def draw_icon(image, xy, box_size, icon, rotation=None): # Increase fontsize to fit specified height and width of text box size = 8 font = ImageFont.truetype(font.path, size) - text_width, text_height = font.getsize(text) + text_width, text_height = font.getbbox(text)[2:] while (text_width < int(box_width * 0.9) and text_height < int(box_height * 0.9)): size += 1 font = ImageFont.truetype(font.path, size) - text_width, text_height = font.getsize(text) + text_width, text_height = font.getbbox(text)[2:] - text_width, text_height = font.getsize(text) + text_width, text_height = font.getbbox(text)[2:] # Align text to desired position x = int((box_width / 2) - (text_width / 2)) - y = int((box_height / 2) - (text_height / 2) - (icon_size_correction[icon] * size) / 2) + y = int((box_height / 2) - (text_height / 2)) # Draw the text in the text-box draw = ImageDraw.Draw(image) space = Image.new('RGBA', (box_width, box_height)) ImageDraw.Draw(space).text((x, y), text, fill='black', font=font) - if rotation != None: + if rotation: space.rotate(rotation, expand=True) # Update only region with text (add text with transparent background) @@ -350,14 +390,9 @@ def draw_icon(image, xy, box_size, icon, rotation=None): temp_fc4 = (col7, row3) # Create current-weather and weather-forecast objects - if self.location.isdigit(): - logging.debug('looking up location by ID') - weather = self.owm.weather_at_id(int(self.location)).weather - forecast = self.owm.forecast_at_id(int(self.location), '3h') - else: - logging.debug('looking up location by string') - weather = self.owm.weather_at_place(self.location).weather - forecast = self.owm.forecast_at_place(self.location, '3h') + logging.debug('looking up location by ID') + weather = self.owm.get_current_weather() + forecast = self.owm.get_weather_forecast() # Set decimals dec_temp = None if self.round_temperature == True else 1 @@ -369,12 +404,14 @@ def draw_icon(image, xy, box_size, icon, rotation=None): elif self.units == 'imperial': temp_unit = 'fahrenheit' - logging.debug(f'temperature unit: {temp_unit}') + logging.debug(f'temperature unit: {self.units}') logging.debug(f'decimals temperature: {dec_temp} | decimals wind: {dec_wind}') # Get current time now = arrow.utcnow() + fc_data = {} + if self.forecast_interval == 'hourly': logger.debug("getting hourly forecasts") @@ -386,21 +423,22 @@ def draw_icon(image, xy, box_size, icon, rotation=None): else: hour_gap = 3 - # Create timings for hourly forcasts + # Create timings for hourly forecasts forecast_timings = [now.shift(hours=+ hour_gap + _).floor('hour') for _ in range(0, 12, 3)] # Create forecast objects for given timings - forecasts = [forecast.get_weather_at(forecast_time.datetime) for - forecast_time in forecast_timings] + forecasts = [_ for _ in forecast if arrow.get(_["dt"]) in forecast_timings] # Add forecast-data to fc_data dictionary fc_data = {} for forecast in forecasts: - temp = '{}°'.format(round( - forecast.temperature(unit=temp_unit)['temp'], ndigits=dec_temp)) + if self.units == "metric": + temp = f"{round(weather['main']['temp'], ndigits=dec_temp)}°C" + else: + temp = f"{round(self.celsius_to_fahrenheit(weather['weather']['main']['temp']), ndigits=dec_temp)}°F" - icon = forecast.weather_icon_name + icon = forecast["weather"][0]["icon"] fc_data['fc' + str(forecasts.index(forecast) + 1)] = { 'temp': temp, 'icon': icon, @@ -412,38 +450,35 @@ def draw_icon(image, xy, box_size, icon, rotation=None): logger.debug("getting daily forecasts") - def calculate_forecast(days_from_today): + def calculate_forecast(days_from_today) -> dict: """Get temperature range and most frequent icon code for forecast days_from_today should be int from 1-4: e.g. 2 -> 2 days from today """ # Create a list containing time-objects for every 3rd hour of the day - time_range = list(arrow.Arrow.range('hour', - now.shift(days=days_from_today).floor('day'), - now.shift(days=days_from_today).ceil('day') - ))[::3] + time_range = list( + arrow.Arrow.range('hour', + now.shift(days=days_from_today).floor('day'),now.shift(days=days_from_today).ceil('day') + ))[::3] # Get forecasts for each time-object - forecasts = [forecast.get_weather_at(_.datetime) for _ in time_range] + forecasts = [_ for _ in forecast if arrow.get(_["dt"]) in time_range] # Get all temperatures for this day - daily_temp = [round(_.temperature(unit=temp_unit)['temp'], - ndigits=dec_temp) for _ in forecasts] + daily_temp = [round(_["main"]["temp"]) for _ in forecasts] # Calculate min. and max. temp for this day - temp_range = f'{max(daily_temp)}°/{min(daily_temp)}°' + temp_range = f'{min(daily_temp)}°/{max(daily_temp)}°' # Get all weather icon codes for this day - daily_icons = [_.weather_icon_name for _ in forecasts] + daily_icons = [_["weather"][0]["icon"] for _ in forecasts] # Find most common element from all weather icon codes status = max(set(daily_icons), key=daily_icons.count) - weekday = now.shift(days=days_from_today).format('ddd', locale= - self.locale) + weekday = now.shift(days=days_from_today).format('ddd', locale=self.locale) return {'temp': temp_range, 'icon': status, 'stamp': weekday} forecasts = [calculate_forecast(days) for days in range(1, 5)] - fc_data = {} for forecast in forecasts: fc_data['fc' + str(forecasts.index(forecast) + 1)] = { 'temp': forecast['temp'], @@ -455,13 +490,15 @@ def calculate_forecast(days_from_today): logger.debug((key, val)) # Get some current weather details - temperature = '{}°'.format(round( - weather.temperature(unit=temp_unit)['temp'], ndigits=dec_temp)) + if dec_temp != 0: + temperature = f"{round(weather['main']['temp'])}°" + else: + temperature = f"{round(weather['main']['temp'],ndigits=dec_temp)}°" - weather_icon = weather.weather_icon_name - humidity = str(weather.humidity) - sunrise_raw = arrow.get(weather.sunrise_time()).to(self.timezone) - sunset_raw = arrow.get(weather.sunset_time()).to(self.timezone) + weather_icon = weather["weather"][0]["icon"] + humidity = str(weather["main"]["humidity"]) + sunrise_raw = arrow.get(weather["sys"]["sunrise"]).to(self.timezone) + sunset_raw = arrow.get(weather["sys"]["sunset"]).to(self.timezone) logger.debug(f'weather_icon: {weather_icon}') @@ -469,33 +506,29 @@ def calculate_forecast(days_from_today): logger.debug('using 12 hour format for sunrise/sunset') sunrise = sunrise_raw.format('h:mm a') sunset = sunset_raw.format('h:mm a') - - elif self.hour_format == 24: + else: + # 24 hours format logger.debug('using 24 hour format for sunrise/sunset') sunrise = sunrise_raw.format('H:mm') sunset = sunset_raw.format('H:mm') - # Format the windspeed to user preference + # Format the wind-speed to user preference if self.use_beaufort: logger.debug("using beaufort for wind") - wind = str(weather.wind(unit='beaufort')['speed']) - + wind = str(self.mps_to_beaufort(weather["wind"]["speed"])) else: - if self.units == 'metric': - logging.debug('getting windspeed in metric unit') - wind = str(weather.wind(unit='meters_sec')['speed']) + 'm/s' - - elif self.units == 'imperial': - logging.debug('getting windspeed in imperial unit') - wind = str(weather.wind(unit='miles_hour')['speed']) + 'miles/h' + logging.debug('getting wind speed in meters per second') + wind = f"{weather['wind']['speed']} m/s" + else: + logging.debug('getting wind speed in imperial unit') + wind = f"{self.mps_to_mph(weather['wind']['speed'])} miles/h" - dec = decimal.Decimal - moonphase = get_moon_phase() + moon_phase = get_moon_phase() # Fill weather details in col 1 (current weather icon) draw_icon(im_colour, weather_icon_pos, (col_width, im_height), - weathericons[weather_icon]) + weather_icons[weather_icon]) # Fill weather details in col 2 (temp, humidity, wind) draw_icon(im_colour, temperature_icon_pos, (icon_small, row_height), @@ -521,7 +554,7 @@ def calculate_forecast(days_from_today): wind, font=self.font) # Fill weather details in col 3 (moonphase, sunrise, sunset) - draw_icon(im_colour, moonphase_pos, (col_width, row_height), moonphase) + draw_icon(im_colour, moonphase_pos, (col_width, row_height), moon_phase) draw_icon(im_colour, sunrise_icon_pos, (icon_small, icon_small), '\uf051') write(im_black, sunrise_time_pos, (col_width - icon_small, row_height), @@ -535,7 +568,7 @@ def calculate_forecast(days_from_today): for pos in range(1, len(fc_data) + 1): stamp = fc_data[f'fc{pos}']['stamp'] - icon = weathericons[fc_data[f'fc{pos}']['icon']] + icon = weather_icons[fc_data[f'fc{pos}']['icon']] temp = fc_data[f'fc{pos}']['temp'] write(im_black, eval(f'stamp_fc{pos}'), (col_width, row_height), @@ -548,7 +581,7 @@ def calculate_forecast(days_from_today): border_h = row3 + row_height border_w = col_width - 3 # leave 3 pixels gap - # Add borders around each sub-section + # Add borders around each subsection draw_border(im_black, (col1, row1), (col_width * 3 - 3, border_h), shrinkage=(0, 0)) diff --git a/inkycal/tests/__init__.py b/inkycal/tests/__init__.py index 34e05a56..cca5d9bd 100644 --- a/inkycal/tests/__init__.py +++ b/inkycal/tests/__init__.py @@ -1 +1 @@ -from config import Config +from .config import Config diff --git a/inkycal/tests/ical_parser_test.py b/inkycal/tests/test_ical_parser.py similarity index 100% rename from inkycal/tests/ical_parser_test.py rename to inkycal/tests/test_ical_parser.py diff --git a/inkycal/tests/inkycal_agenda_test.py b/inkycal/tests/test_inkycal_agenda.py similarity index 100% rename from inkycal/tests/inkycal_agenda_test.py rename to inkycal/tests/test_inkycal_agenda.py diff --git a/inkycal/tests/inkycal_calendar_test.py b/inkycal/tests/test_inkycal_calendar.py similarity index 100% rename from inkycal/tests/inkycal_calendar_test.py rename to inkycal/tests/test_inkycal_calendar.py diff --git a/inkycal/tests/inkycal_feeds_test.py b/inkycal/tests/test_inkycal_feeds.py similarity index 96% rename from inkycal/tests/inkycal_feeds_test.py rename to inkycal/tests/test_inkycal_feeds.py index dfdab9b8..30f9613b 100755 --- a/inkycal/tests/inkycal_feeds_test.py +++ b/inkycal/tests/test_inkycal_feeds.py @@ -57,8 +57,6 @@ def test_generate_image(self): print('OK') if Config.USE_PREVIEW: preview(merge(im_black, im_colour)) - im = merge(im_black, im_colour) - im.show() if __name__ == '__main__': diff --git a/inkycal/tests/inkycal_image_test.py b/inkycal/tests/test_inkycal_image.py similarity index 100% rename from inkycal/tests/inkycal_image_test.py rename to inkycal/tests/test_inkycal_image.py diff --git a/inkycal/tests/inkycal_jokes_test.py b/inkycal/tests/test_inkycal_jokes.py similarity index 100% rename from inkycal/tests/inkycal_jokes_test.py rename to inkycal/tests/test_inkycal_jokes.py diff --git a/inkycal/tests/inkycal_slideshow_test.py b/inkycal/tests/test_inkycal_slideshow.py similarity index 100% rename from inkycal/tests/inkycal_slideshow_test.py rename to inkycal/tests/test_inkycal_slideshow.py diff --git a/inkycal/tests/inkycal_stocks_test.py b/inkycal/tests/test_inkycal_stocks.py similarity index 100% rename from inkycal/tests/inkycal_stocks_test.py rename to inkycal/tests/test_inkycal_stocks.py diff --git a/inkycal/tests/test_inkycal_textfile_to_display.py b/inkycal/tests/test_inkycal_textfile_to_display.py index 11c548ab..92afb74b 100644 --- a/inkycal/tests/test_inkycal_textfile_to_display.py +++ b/inkycal/tests/test_inkycal_textfile_to_display.py @@ -112,8 +112,6 @@ def test_generate_image(self): print('OK') if Config.USE_PREVIEW: preview(merge(im_black, im_colour)) - im = merge(im_black, im_colour) - im.show() if delete_file_after_parse: print("cleaning up temp file") diff --git a/inkycal/tests/inkycal_todoist_test.py b/inkycal/tests/test_inkycal_todoist.py similarity index 96% rename from inkycal/tests/inkycal_todoist_test.py rename to inkycal/tests/test_inkycal_todoist.py index 63e579fd..bf87cafa 100644 --- a/inkycal/tests/inkycal_todoist_test.py +++ b/inkycal/tests/test_inkycal_todoist.py @@ -46,7 +46,6 @@ def test_generate_image(self): print('OK') if Config.USE_PREVIEW: preview(merge(im_black, im_colour)) - merge(im_black, im_colour).show() else: print('No api key given, omitting test') diff --git a/inkycal/tests/inkycal_weather_test.py b/inkycal/tests/test_inkycal_weather.py similarity index 98% rename from inkycal/tests/inkycal_weather_test.py rename to inkycal/tests/test_inkycal_weather.py index 8682bec4..b6bde428 100755 --- a/inkycal/tests/inkycal_weather_test.py +++ b/inkycal/tests/test_inkycal_weather.py @@ -13,7 +13,7 @@ merge = Inkyimage.merge owm_api_key = Config.OPENWEATHERMAP_API_KEY -location = 'Stuttgart, DE' +location = '2825297' tests = [ { @@ -184,7 +184,8 @@ def test_generate_image(self): im_black, im_colour = module.generate_image() print('OK') if Config.USE_PREVIEW: - preview(merge(im_black, im_colour)) + merged = merge(im_black, im_colour) + preview(merged) diff --git a/requirements.txt b/requirements.txt index 5186aa21..1d9ca8d1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,30 +1,25 @@ -arrow==1.2.3 +arrow==1.3.0 certifi==2023.7.22 -cycler==0.11.0 +cycler==0.12.1 feedparser==6.0.10 -fonttools==4.40.0 -geojson==2.3.0 -icalendar==5.0.7 -kiwisolver==1.4.4 -lxml==4.9.2 -matplotlib==3.7.1 -multitasking==0.0.11 -numpy==1.25.0 -packaging==23.1 -pandas==2.0.2 -Pillow==9.5.0 -pyowm==3.3.0 -pyparsing==3.1.0 +fonttools==4.44.0 +icalendar==5.0.11 +kiwisolver==1.4.5 +lxml==4.9.3 +matplotlib==3.8.1 +numpy==1.26.1 +packaging==23.2 +Pillow==10.1.0 +pyparsing==3.1.1 PySocks==1.7.1 python-dateutil==2.8.2 -pytz==2023.3 -recurring-ical-events==2.0.2 +pytz==2023.3.post1 +recurring-ical-events==2.1.0 requests==2.31.0 sgmllib3k==1.0.0 six==1.16.0 -todoist-api-python==2.0.2 -typing_extensions==4.6.3 +todoist-api-python==2.1.3 +typing_extensions==4.8.0 urllib3==2.0.7 -yfinance==0.2.21 python-dotenv==1.0.0 -setuptools==68.0.0 +setuptools==68.2.2