diff --git a/docs/inkycal.html b/docs/inkycal.html
index 2166d2b..e098b4e 100644
--- a/docs/inkycal.html
+++ b/docs/inkycal.html
@@ -232,14 +232,14 @@ which the given font should be scaled to.
-
-inkycal.custom.functions.draw_border(image, xy, size, radius=5, thickness=1, shrinkage=(0.1, 0.1))
+inkycal.custom.functions.draw_border(image: <module 'PIL.Image' from '/home/runner/work/Inkycal/Inkycal/venv/lib/python3.11/site-packages/PIL/Image.py'>, xy: ~typing.Tuple[int, int], size: ~typing.Tuple[int, int], radius: int = 5, thickness: int = 1, shrinkage: ~typing.Tuple[int, int] = (0.1, 0.1)) → None
Draws a border at given coordinates.
- Args:
image: The image on which the border should be drawn (usually im_black or
-im_colour.
+im_colour).
xy: Tuple representing the top-left corner of the border e.g. (32, 100)
-where 32 is the x co-ordinate and 100 is the y-coordinate.
+where 32 is the x-coordinate and 100 is the y-coordinate.
size: Size of the border as a tuple -> (width, height).
radius: Radius of the corners, where 0 = plain rectangle, 5 = round corners.
thickness: Thickness of the border in pixels.
@@ -288,14 +288,14 @@ printed fonts of this function:
The extracted timezone can be used to show the local time instead of UTC. e.g.
>>> import arrow
>>> print(arrow.now()) # returns non-timezone-aware time
->>> print(arrow.now(tz=get_system_tz()) # prints timezone aware time.
+>>> print(arrow.now(tz=get_system_tz())) # prints timezone aware time.
-
-inkycal.custom.functions.internet_available()
+inkycal.custom.functions.internet_available() → bool
checks if the internet is available.
Attempts to connect to google.com with a timeout of 5 seconds to check
if the network can be reached.
@@ -315,7 +315,7 @@ if the network can be reached.
-
-inkycal.custom.functions.text_wrap(text, font=None, max_width=None)
+inkycal.custom.functions.text_wrap(text: str, font=None, max_width=None)
Splits a very long text into smaller parts
Splits a long text to smaller lines which can fit in a line with max_width.
Uses a Font object for more accurate calculations.
@@ -334,7 +334,7 @@ splitting the text into the next chunk.
-
-inkycal.custom.functions.write(image, xy, box_size, text, font=None, **kwargs)
+inkycal.custom.functions.write(image: <module 'PIL.Image' from '/home/runner/work/Inkycal/Inkycal/venv/lib/python3.11/site-packages/PIL/Image.py'>, xy: ~typing.Tuple[int, int], box_size: ~typing.Tuple[int, int], text: str, font=None, **kwargs)
Writes text on an image.
Writes given text at given position on the specified image.
diff --git a/fonts/MaterialIcons/MaterialIcons.ttf b/fonts/MaterialIcons/MaterialIcons.ttf
new file mode 100644
index 0000000..9d09b0f
Binary files /dev/null and b/fonts/MaterialIcons/MaterialIcons.ttf differ
diff --git a/inkycal/custom/functions.py b/inkycal/custom/functions.py
index 206a2ec..2c39b76 100644
--- a/inkycal/custom/functions.py
+++ b/inkycal/custom/functions.py
@@ -8,9 +8,9 @@ import logging
import os
import time
import traceback
+from typing import Tuple
import arrow
-import PIL
import requests
import tzlocal
from PIL import Image
@@ -73,7 +73,7 @@ def get_system_tz() -> str:
>>> import arrow
>>> print(arrow.now()) # returns non-timezone-aware time
- >>> print(arrow.now(tz=get_system_tz()) # prints timezone aware time.
+ >>> print(arrow.now(tz=get_system_tz())) # prints timezone aware time.
"""
try:
local_tz = tzlocal.get_localzone().key
@@ -111,7 +111,7 @@ def auto_fontsize(font, max_height):
return font
-def write(image, xy, box_size, text, font=None, **kwargs):
+def write(image: Image, xy: Tuple[int, int], box_size: Tuple[int, int], text: str, font=None, **kwargs):
"""Writes text on an image.
Writes given text at given position on the specified image.
@@ -161,7 +161,7 @@ def write(image, xy, box_size, text, font=None, **kwargs):
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_height = abs(text_bbox_height[3]) # - abs(text_bbox_height[1])
while text_width < int(box_width * fill_width) and text_height < int(box_height * fill_height):
size += 1
@@ -169,12 +169,12 @@ def write(image, xy, box_size, text, font=None, **kwargs):
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_height = abs(text_bbox_height[3]) # - abs(text_bbox_height[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_height = abs(text_bbox_height[3]) # - abs(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):
@@ -184,7 +184,7 @@ def write(image, xy, box_size, text, font=None, **kwargs):
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_height = abs(text_bbox_height[3]) # - abs(text_bbox_height[1])
logger.debug(text)
# Align text to desired position
@@ -195,10 +195,13 @@ def write(image, xy, box_size, text, font=None, **kwargs):
elif alignment == "right":
x = int(box_width - text_width)
+ # Vertical centering
+ 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, 0), text, fill=colour, font=font)
+ ImageDraw.Draw(space).text((x, y), text, fill=colour, font=font)
# Uncomment following two lines, comment out above two lines to show
# red text-box with white text (debugging purposes)
@@ -213,7 +216,7 @@ def write(image, xy, box_size, text, font=None, **kwargs):
image.paste(space, xy, space)
-def text_wrap(text, font=None, max_width=None):
+def text_wrap(text: str, font=None, max_width=None):
"""Splits a very long text into smaller parts
Splits a long text to smaller lines which can fit in a line with max_width.
@@ -249,7 +252,7 @@ def text_wrap(text, font=None, max_width=None):
return lines
-def internet_available():
+def internet_available() -> bool:
"""checks if the internet is available.
Attempts to connect to google.com with a timeout of 5 seconds to check
@@ -274,15 +277,16 @@ def internet_available():
return False
-def draw_border(image, xy, size, radius=5, thickness=1, shrinkage=(0.1, 0.1)):
+def draw_border(image: Image, xy: Tuple[int, int], size: Tuple[int, int], radius: int = 5, thickness: int = 1,
+ shrinkage: Tuple[int, int] = (0.1, 0.1)) -> None:
"""Draws a border at given coordinates.
Args:
- image: The image on which the border should be drawn (usually im_black or
- im_colour.
+ im_colour).
- xy: Tuple representing the top-left corner of the border e.g. (32, 100)
- where 32 is the x co-ordinate and 100 is the y-coordinate.
+ where 32 is the x-coordinate and 100 is the y-coordinate.
- size: Size of the border as a tuple -> (width, height).
@@ -320,6 +324,7 @@ def draw_border(image, xy, size, radius=5, thickness=1, shrinkage=(0.1, 0.1)):
c5, c6 = ((x + width) - diameter, (y + height) - diameter), (x + width, y + height)
c7, c8 = (x, (y + height) - diameter), (x + diameter, y + height)
+
# Draw lines and arcs, creating a square with round corners
draw = ImageDraw.Draw(image)
draw.line((p1, p2), fill=colour, width=thickness)
@@ -334,7 +339,7 @@ def draw_border(image, xy, size, radius=5, thickness=1, shrinkage=(0.1, 0.1)):
draw.arc((c7, c8), 90, 180, fill=colour, width=thickness)
-def draw_border_2(im: PIL.Image, xy: tuple, size: tuple, radius: int):
+def draw_border_2(im: Image, xy: Tuple[int, int], size: Tuple[int, int], radius: int):
draw = ImageDraw.Draw(im)
x, y = xy
diff --git a/inkycal/custom/openweathermap_wrapper.py b/inkycal/custom/openweathermap_wrapper.py
index 6cd4405..779c5bf 100644
--- a/inkycal/custom/openweathermap_wrapper.py
+++ b/inkycal/custom/openweathermap_wrapper.py
@@ -41,18 +41,9 @@ def get_json_from_url(request_url):
class OpenWeatherMap:
- def __init__(
- self,
- api_key: str,
- city_id: int = None,
- lat: float = None,
- lon: float = None,
- api_version: API_VERSIONS = "2.5",
- temp_unit: TEMP_UNITS = "celsius",
- wind_unit: WIND_UNITS = "meters_sec",
- language: str = "en",
- tz_name: str = "UTC",
- ) -> None:
+ def __init__(self, api_key: str, city_id: int = None, lat: float = None, lon: float = None,
+ api_version: API_VERSIONS = "2.5", temp_unit: TEMP_UNITS = "celsius",
+ wind_unit: WIND_UNITS = "meters_sec", language: str = "en", tz_name: str = "UTC") -> None:
self.api_key = api_key
self.temp_unit = temp_unit
self.wind_unit = wind_unit
@@ -106,7 +97,7 @@ class OpenWeatherMap:
current_weather["temp_feels_like"] = self.get_converted_temperature(current_data["main"]["feels_like"])
current_weather["min_temp"] = self.get_converted_temperature(current_data["main"]["temp_min"])
current_weather["max_temp"] = self.get_converted_temperature(current_data["main"]["temp_max"])
- current_weather["humidity"] = current_data["main"]["humidity"] # OWM Unit: % rH
+ current_weather["humidity"] = current_data["main"]["humidity"] # OWM Unit: % rH
current_weather["wind"] = self.get_converted_windspeed(
current_data["wind"]["speed"]
) # OWM Unit Default: meter/sec, Metric: meter/sec
@@ -161,10 +152,10 @@ class OpenWeatherMap:
forecast["wind"]["speed"]
), # OWM Unit Default: meter/sec, Metric: meter/sec, Imperial: miles/hour
"wind_gust": self.get_converted_windspeed(forecast["wind"]["gust"]),
- "pressure": forecast["main"]["pressure"], # OWM Unit: hPa
- "humidity": forecast["main"]["humidity"], # OWM Unit: % rH
+ "pressure": forecast["main"]["pressure"], # OWM Unit: hPa
+ "humidity": forecast["main"]["humidity"], # OWM Unit: % rH
"precip_probability": forecast["pop"]
- * 100.0, # OWM value is unitless, directly converting to % scale
+ * 100.0, # OWM value is unitless, directly converting to % scale
"icon": forecast["weather"][0]["icon"],
"datetime": datetime.fromtimestamp(forecast["dt"], tz=self.tz_zone),
}
@@ -187,7 +178,7 @@ class OpenWeatherMap:
:return:
Forecast dictionary
"""
- # Make sure hourly forecasts are up to date
+ # Make sure hourly forecasts are up-to-date
_ = self.get_weather_forecast()
# Calculate the start and end times for the specified number of days from now
@@ -207,7 +198,7 @@ class OpenWeatherMap:
]
# In case the next available forecast is already for the next day, use that one for the less than 3 remaining hours of today
- if forecasts == []:
+ if not forecasts:
forecasts.append(self.hourly_forecasts[0])
# Get rain and temperatures for that day
diff --git a/inkycal/modules/inkycal_agenda.py b/inkycal/modules/inkycal_agenda.py
index a91f93b..1508a66 100755
--- a/inkycal/modules/inkycal_agenda.py
+++ b/inkycal/modules/inkycal_agenda.py
@@ -75,6 +75,8 @@ class Agenda(inkycal_module):
# Additional config
self.timezone = get_system_tz()
+ self.icon_font = ImageFont.truetype(fonts['MaterialIcons'], size=self.fontsize)
+
# give an OK message
logger.debug(f'{__name__} loaded')
@@ -201,10 +203,10 @@ class Agenda(inkycal_module):
write(im_black, (x_time, line_pos[cursor][1]),
(time_width, line_height), time,
font=self.font, alignment='right')
- if parser.all_day(_):
+ else:
write(im_black, (x_time, line_pos[cursor][1]),
- (time_width, line_height), "all day",
- font=self.font, alignment='right')
+ (time_width, line_height), "\ue878",
+ font=self.icon_font, alignment='right')
write(im_black, (x_event, line_pos[cursor][1]),
(event_width, line_height),
diff --git a/inkycal/modules/inkycal_calendar.py b/inkycal/modules/inkycal_calendar.py
index 0f947cd..146c272 100755
--- a/inkycal/modules/inkycal_calendar.py
+++ b/inkycal/modules/inkycal_calendar.py
@@ -6,16 +6,16 @@ Copyright by aceinnolab
# pylint: disable=logging-fstring-interpolation
import calendar as cal
-import arrow
-from inkycal.modules.template import inkycal_module
+
from inkycal.custom import *
+from inkycal.modules.template import inkycal_module
logger = logging.getLogger(__name__)
class Calendar(inkycal_module):
"""Calendar class
- Create monthly calendar and show events from given icalendars
+ Create monthly calendar and show events from given iCalendars
"""
name = "Calendar - Show monthly calendar with events from iCalendars"
@@ -39,12 +39,12 @@ class Calendar(inkycal_module):
},
"date_format": {
"label": "Use an arrow-supported token for custom date formatting "
- + "see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. D MMM",
+ + "see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. D MMM",
"default": "D MMM",
},
"time_format": {
"label": "Use an arrow-supported token for custom time formatting "
- + "see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. HH:mm",
+ + "see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. HH:mm",
"default": "HH:mm",
},
}
@@ -61,7 +61,7 @@ class Calendar(inkycal_module):
self._days_with_events = None
# optional parameters
- self.weekstart = config['week_starts_on']
+ self.week_start = config['week_starts_on']
self.show_events = config['show_events']
self.date_format = config["date_format"]
self.time_format = config['time_format']
@@ -109,7 +109,7 @@ class Calendar(inkycal_module):
# Allocate space for month-names, weekdays etc.
month_name_height = int(im_height * 0.10)
text_bbox_height = self.font.getbbox("hg")
- weekdays_height = int((text_bbox_height[3] - text_bbox_height[1]) * 1.25)
+ weekdays_height = int((abs(text_bbox_height[3]) + abs(text_bbox_height[1])) * 1.25)
logger.debug(f"month_name_height: {month_name_height}")
logger.debug(f"weekdays_height: {weekdays_height}")
@@ -117,7 +117,7 @@ class Calendar(inkycal_module):
logger.debug("Allocating space for events")
calendar_height = int(im_height * 0.6)
events_height = (
- im_height - month_name_height - weekdays_height - calendar_height
+ im_height - month_name_height - weekdays_height - calendar_height
)
logger.debug(f'calendar-section size: {im_width} x {calendar_height} px')
logger.debug(f'events-section size: {im_width} x {events_height} px')
@@ -156,13 +156,13 @@ class Calendar(inkycal_module):
now = arrow.now(tz=self.timezone)
- # Set weekstart of calendar to specified weekstart
- if self.weekstart == "Monday":
+ # Set week-start of calendar to specified week-start
+ if self.week_start == "Monday":
cal.setfirstweekday(cal.MONDAY)
- weekstart = now.shift(days=-now.weekday())
+ week_start = now.shift(days=-now.weekday())
else:
cal.setfirstweekday(cal.SUNDAY)
- weekstart = now.shift(days=-now.isoweekday())
+ week_start = now.shift(days=-now.isoweekday())
# Write the name of current month
write(
@@ -174,9 +174,9 @@ class Calendar(inkycal_module):
autofit=True,
)
- # Set up weeknames in local language and add to main section
+ # Set up week-names in local language and add to main section
weekday_names = [
- weekstart.shift(days=+_).format('ddd', locale=self.language)
+ week_start.shift(days=+_).format('ddd', locale=self.language)
for _ in range(7)
]
logger.debug(f'weekday names: {weekday_names}')
@@ -192,7 +192,7 @@ class Calendar(inkycal_module):
fill_height=0.9,
)
- # Create a calendar template and flatten (remove nestings)
+ # Create a calendar template and flatten (remove nesting)
calendar_flat = self.flatten(cal.monthcalendar(now.year, now.month))
# logger.debug(f" calendar_flat: {calendar_flat}")
@@ -281,7 +281,7 @@ class Calendar(inkycal_module):
month_start = arrow.get(now.floor('month'))
month_end = arrow.get(now.ceil('month'))
- # fetch events from given icalendars
+ # fetch events from given iCalendars
self.ical = iCalendar()
parser = self.ical
@@ -294,14 +294,12 @@ class Calendar(inkycal_module):
month_events = parser.get_events(month_start, month_end, self.timezone)
parser.sort()
self.month_events = month_events
-
+
# Initialize days_with_events as an empty list
days_with_events = []
# Handle multi-day events by adding all days between start and end
for event in month_events:
- start_date = event['begin'].date()
- end_date = event['end'].date()
# Convert start and end dates to arrow objects with timezone
start = arrow.get(event['begin'].date(), tzinfo=self.timezone)
@@ -324,9 +322,7 @@ class Calendar(inkycal_module):
im_colour,
grid[days],
(icon_width, icon_height),
- radius=6,
- thickness=1,
- shrinkage=(0, 0),
+ radius=6
)
# Filter upcoming events until 4 weeks in the future
@@ -345,13 +341,13 @@ class Calendar(inkycal_module):
date_width = int(max((
self.font.getlength(events['begin'].format(self.date_format, locale=lang))
- for events in upcoming_events))* 1.1
- )
+ 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
- )
+ for events in upcoming_events)) * 1.1
+ )
text_bbox_height = self.font.getbbox("hg")
line_height = text_bbox_height[3] + line_spacing
@@ -369,7 +365,8 @@ class Calendar(inkycal_module):
event_duration = (event['end'] - event['begin']).days
if event_duration > 1:
# Format the duration using Arrow's localization
- days_translation = arrow.get().shift(days=event_duration).humanize(only_distance=True, locale=lang)
+ days_translation = arrow.get().shift(days=event_duration).humanize(only_distance=True,
+ locale=lang)
the_name = f"{event['title']} ({days_translation})"
else:
the_name = event['title']
diff --git a/inkycal/modules/inkycal_weather.py b/inkycal/modules/inkycal_weather.py
index 8bfe2c2..2c32b0b 100644
--- a/inkycal/modules/inkycal_weather.py
+++ b/inkycal/modules/inkycal_weather.py
@@ -2,12 +2,12 @@
Inkycal weather module
Copyright by aceinnolab
"""
-
-import arrow
import decimal
import logging
import math
+from typing import Tuple
+import arrow
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
@@ -51,7 +51,7 @@ class Weather(inkycal_module):
"options": [True, False],
},
- "round_windspeed": {
+ "round_wind_speed": {
"label": "Round windspeed?",
"options": [True, False],
},
@@ -89,7 +89,7 @@ class Weather(inkycal_module):
# Check if all required parameters are present
for param in self.requires:
- if not param in config:
+ if param not in config:
raise Exception(f'config is missing {param}')
# required parameters
@@ -98,15 +98,15 @@ class Weather(inkycal_module):
# optional parameters
self.round_temperature = config['round_temperature']
- self.round_windspeed = config['round_windspeed']
+ self.round_wind_speed = config['round_windspeed']
self.forecast_interval = config['forecast_interval']
self.hour_format = int(config['hour_format'])
if config['units'] == "imperial":
self.temp_unit = "fahrenheit"
else:
self.temp_unit = "celsius"
-
- if config['use_beaufort'] == True:
+
+ if config['use_beaufort']:
self.wind_unit = "beaufort"
elif config['units'] == "imperial":
self.wind_unit = "miles_hour"
@@ -116,17 +116,17 @@ class Weather(inkycal_module):
# additional configuration
self.owm = OpenWeatherMap(
- api_key=self.api_key,
- city_id=self.location,
- wind_unit=self.wind_unit,
+ api_key=self.api_key,
+ city_id=self.location,
+ wind_unit=self.wind_unit,
temp_unit=self.temp_unit,
- language=self.locale,
+ language=self.locale,
tz_name=self.timezone
- )
-
+ )
+
self.weatherfont = ImageFont.truetype(
fonts['weathericons-regular-webfont'], size=self.fontsize)
-
+
if self.wind_unit == "beaufort":
self.windDispUnit = "bft"
elif self.wind_unit == "knots":
@@ -145,8 +145,6 @@ class Weather(inkycal_module):
# give an OK message
logger.debug(f"{__name__} loaded")
-
-
def generate_image(self):
"""Generate image for this module"""
@@ -191,7 +189,7 @@ class Weather(inkycal_module):
7: '\uf0ae'
}[int(index) & 7]
- def is_negative(temp:str):
+ def is_negative(temp: str):
"""Check if temp is below freezing point of water (0°C/32°F)
returns True if temp below freezing point, else False"""
answer = False
@@ -224,12 +222,19 @@ class Weather(inkycal_module):
'50n': '\uf023'
}
- def draw_icon(image, xy, box_size, icon, rotation=None):
- """Custom function to add icons of weather font on image
- image = on which image should the text be added?
- xy = xy-coordinates as tuple -> (x,y)
- box_size = size of text-box -> (width,height)
- icon = icon-unicode, looks this up in weathericons dictionary
+ def draw_icon(image: Image, xy: Tuple[int, int], box_size: Tuple[int, int], icon: str, rotation=None):
+ """Custom function to add icons of weather font on the image.
+
+ Args:
+ - image:
+ the image on which image should the text be added
+ - xy:
+ coordinates as tuple -> (x,y)
+ - box_size:
+ size of text-box -> (width,height)
+ - icon:
+ icon-unicode, looks this up in weather-icons dictionary
+
"""
icon_size_correction = {
@@ -264,7 +269,6 @@ class Weather(inkycal_module):
'\uf0a0': 0,
'\uf0a3': 0,
'\uf0a7': 0,
- '\uf0aa': 0,
'\uf0ae': 0
}
@@ -278,8 +282,7 @@ class Weather(inkycal_module):
font = ImageFont.truetype(font.path, size)
text_width, text_height = font.getbbox(text)[2:]
- while (text_width < int(box_width * 0.9) and
- text_height < int(box_height * 0.9)):
+ 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.getbbox(text)[2:]
@@ -290,8 +293,6 @@ class Weather(inkycal_module):
x = int((box_width / 2) - (text_width / 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)
@@ -350,17 +351,17 @@ class Weather(inkycal_module):
row3 = row2 + line_gap + row_height
# Draw lines on each row and border
- ############################################################################
- ## draw = ImageDraw.Draw(im_black)
- ## draw.line((0, 0, im_width, 0), fill='red')
- ## draw.line((0, im_height-1, im_width, im_height-1), fill='red')
- ## draw.line((0, row1, im_width, row1), fill='black')
- ## draw.line((0, row1+row_height, im_width, row1+row_height), fill='black')
- ## draw.line((0, row2, im_width, row2), fill='black')
- ## draw.line((0, row2+row_height, im_width, row2+row_height), fill='black')
- ## draw.line((0, row3, im_width, row3), fill='black')
- ## draw.line((0, row3+row_height, im_width, row3+row_height), fill='black')
- ############################################################################
+ ###########################################################################
+ # draw = ImageDraw.Draw(im_black)
+ # draw.line((0, 0, im_width, 0), fill='red')
+ # draw.line((0, im_height-1, im_width, im_height-1), fill='red')
+ # draw.line((0, row1, im_width, row1), fill='black')
+ # draw.line((0, row1+row_height, im_width, row1+row_height), fill='black')
+ # draw.line((0, row2, im_width, row2), fill='black')
+ # draw.line((0, row2+row_height, im_width, row2+row_height), fill='black')
+ # draw.line((0, row3, im_width, row3), fill='black')
+ # draw.line((0, row3+row_height, im_width, row3+row_height), fill='black')
+ ###########################################################################
# Positions for current weather details
weather_icon_pos = (col1, 0)
@@ -379,24 +380,24 @@ class Weather(inkycal_module):
sunset_time_pos = (col3 + icon_small, row3)
# Positions for forecast 1
- stamp_fc1 = (col4, row1)
- icon_fc1 = (col4, row1 + row_height)
- temp_fc1 = (col4, row3)
+ stamp_fc1 = (col4, row1) # noqa
+ icon_fc1 = (col4, row1 + row_height) # noqa
+ temp_fc1 = (col4, row3) # noqa
# Positions for forecast 2
- stamp_fc2 = (col5, row1)
- icon_fc2 = (col5, row1 + row_height)
- temp_fc2 = (col5, row3)
+ stamp_fc2 = (col5, row1) # noqa
+ icon_fc2 = (col5, row1 + row_height) # noqa
+ temp_fc2 = (col5, row3) # noqa
# Positions for forecast 3
- stamp_fc3 = (col6, row1)
- icon_fc3 = (col6, row1 + row_height)
- temp_fc3 = (col6, row3)
+ stamp_fc3 = (col6, row1) # noqa
+ icon_fc3 = (col6, row1 + row_height) # noqa
+ temp_fc3 = (col6, row3) # noqa
# Positions for forecast 4
- stamp_fc4 = (col7, row1)
- icon_fc4 = (col7, row1 + row_height)
- temp_fc4 = (col7, row3)
+ stamp_fc4 = (col7, row1) # noqa
+ icon_fc4 = (col7, row1 + row_height) # noqa
+ temp_fc4 = (col7, row3) # noqa
# Create current-weather and weather-forecast objects
logging.debug('looking up location by ID')
@@ -405,7 +406,7 @@ class Weather(inkycal_module):
# Set decimals
dec_temp = 0 if self.round_temperature == True else 1
- dec_wind = 0 if self.round_windspeed == True else 1
+ dec_wind = 0 if self.round_wind_speed == True else 1
logging.debug(f'temperature unit: {self.temp_unit}')
logging.debug(f'decimals temperature: {dec_temp} | decimals wind: {dec_wind}')
@@ -425,7 +426,8 @@ class Weather(inkycal_module):
fc_data['fc' + str(index + 1)] = {
'temp': f"{forecast['temp']:.{dec_temp}f}{self.tempDispUnit}",
'icon': forecast["icon"],
- 'stamp': forecast["datetime"].strftime("%I %p" if self.hour_format == 12 else "%H:%M")}
+ 'stamp': forecast["datetime"].strftime("%I %p" if self.hour_format == 12 else "%H:%M")
+ }
elif self.forecast_interval == 'daily':
@@ -434,7 +436,7 @@ class Weather(inkycal_module):
daily_forecasts = [self.owm.get_forecast_for_day(days) for days in range(1, 5)]
for index, forecast in enumerate(daily_forecasts):
- fc_data['fc' + str(index +1)] = {
+ fc_data['fc' + str(index + 1)] = {
'temp': f'{forecast["temp_min"]:.{dec_temp}f}{self.tempDispUnit}/{forecast["temp_max"]:.{dec_temp}f}{self.tempDispUnit}',
'icon': forecast['icon'],
'stamp': forecast['datetime'].strftime("%A")
@@ -514,6 +516,9 @@ class Weather(inkycal_module):
# Add the forecast data to the correct places
for pos in range(1, len(fc_data) + 1):
stamp = fc_data[f'fc{pos}']['stamp']
+ # check if we're using daily forecasts
+ if "day" in stamp:
+ stamp = arrow.get(fc_data[f'fc{pos}']['stamp'], "dddd").format("dddd", locale="de")
icon = weather_icons[fc_data[f'fc{pos}']['icon']]
temp = fc_data[f'fc{pos}']['temp']
diff --git a/inkycal/modules/inkycal_webshot.py b/inkycal/modules/inkycal_webshot.py
index ae49dee..5f72351 100644
--- a/inkycal/modules/inkycal_webshot.py
+++ b/inkycal/modules/inkycal_webshot.py
@@ -41,7 +41,10 @@ class Webshot(inkycal_module):
},
"crop_h": {
"label": "Please enter the crop height",
- }
+ },
+ "rotation": {
+ "label": "Please enter the rotation. Must be either 0, 90, 180 or 270",
+ },
}
def __init__(self, config):
@@ -73,6 +76,12 @@ class Webshot(inkycal_module):
else:
self.crop_y = 0
+ self.rotation = 0
+ if "rotation" in config:
+ self.rotation = int(config["rotation"])
+ if self.rotation not in [0, 90, 180, 270]:
+ raise Exception("Rotation must be either 0, 90, 180 or 270")
+
# give an OK message
logger.debug(f'Inkycal webshot loaded')
@@ -106,7 +115,7 @@ class Webshot(inkycal_module):
logger.info(
f'preparing webshot from {self.url}... cropH{self.crop_h} cropW{self.crop_w} cropX{self.crop_x} cropY{self.crop_y}')
- shot = WebShot()
+ shot = WebShot(size=(im_height, im_width))
shot.params = {
"--crop-x": self.crop_x,
@@ -152,11 +161,21 @@ class Webshot(inkycal_module):
centerPosX = int((im_width / 2) - (im.image.width / 2))
- webshotSpaceBlack.paste(im_webshot_black, (centerPosX, webshotCenterPosY))
- im_black.paste(webshotSpaceBlack)
- webshotSpaceColour.paste(im_webshot_colour, (centerPosX, webshotCenterPosY))
- im_colour.paste(webshotSpaceColour)
+ if self.rotation != 0:
+ webshotSpaceBlack.paste(im_webshot_black, (centerPosX, webshotCenterPosY))
+ im_black.paste(webshotSpaceBlack)
+ im_black = im_black.rotate(self.rotation, expand=True)
+
+ webshotSpaceColour.paste(im_webshot_colour, (centerPosX, webshotCenterPosY))
+ im_colour.paste(webshotSpaceColour)
+ im_colour = im_colour.rotate(self.rotation, expand=True)
+ else:
+ webshotSpaceBlack.paste(im_webshot_black, (centerPosX, webshotCenterPosY))
+ im_black.paste(webshotSpaceBlack)
+
+ webshotSpaceColour.paste(im_webshot_colour, (centerPosX, webshotCenterPosY))
+ im_colour.paste(webshotSpaceColour)
im.clear()
logger.info(f'added webshot image')
diff --git a/requirements.txt b/requirements.txt
index 4554902..75ea61b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -37,7 +37,7 @@ python-dotenv==1.0.1
pytz==2024.1
PyYAML==6.0.1
recurring-ical-events==2.1.2
-requests==2.31.0
+requests==2.32.0
sgmllib3k==1.0.0
six==1.16.0
soupsieve==2.5
@@ -46,7 +46,7 @@ types-python-dateutil==2.8.19.20240106
typing_extensions==4.9.0
tzdata==2024.1
tzlocal==5.2
-urllib3==2.2.0
+urllib3==2.2.2
virtualenv==20.25.0
webencodings==0.5.1
x-wr-timezone==0.0.6
diff --git a/tests/test_functions.py b/tests/test_functions.py
index b624978..0d8a6dd 100644
--- a/tests/test_functions.py
+++ b/tests/test_functions.py
@@ -1,12 +1,22 @@
"""
Test the functions in the functions module.
"""
+import unittest
+
from PIL import Image, ImageFont
-from inkycal.custom import write, fonts
+
+from inkycal.custom import write, fonts, get_system_tz
-def test_write():
- im = Image.new("RGB", (500, 200), "white")
- font = ImageFont.truetype(fonts['NotoSans-SemiCondensed'], size = 40)
- write(im, (125,75), (250, 50), "Hello World", font)
- # im.show()
+class TestIcalendar(unittest.TestCase):
+
+ def test_write(self):
+ im = Image.new("RGB", (500, 200), "white")
+ font = ImageFont.truetype(fonts['NotoSans-SemiCondensed'], size=40)
+ write(im, (125, 75), (250, 50), "Hello World", font)
+ # im.show()
+
+ def test_get_system_tz(self):
+ tz = get_system_tz()
+ assert isinstance(tz, str)
+
diff --git a/tests/test_inkycal_agenda.py b/tests/test_inkycal_agenda.py
index 642f654..685bb86 100755
--- a/tests/test_inkycal_agenda.py
+++ b/tests/test_inkycal_agenda.py
@@ -37,7 +37,7 @@ tests = [
"size": [500, 800],
"ical_urls": sample_url,
"ical_files": None,
- "date_format": "ddd D MMM",
+ "date_format": "DD.MMMM YYYY",
"time_format": "HH:mm",
"padding_x": 10,
"padding_y": 10,
diff --git a/tests/test_inkycal_calendar.py b/tests/test_inkycal_calendar.py
index cb28b9a..434d5d8 100755
--- a/tests/test_inkycal_calendar.py
+++ b/tests/test_inkycal_calendar.py
@@ -20,7 +20,7 @@ tests = [
{
"name": "Calendar",
"config": {
- "size": [500, 500],
+ "size": [500, 600],
"week_starts_on": "Monday",
"show_events": True,
"ical_urls": sample_url,
diff --git a/tests/test_inkycal_weather.py b/tests/test_inkycal_weather.py
index bcc50ce..2325616 100755
--- a/tests/test_inkycal_weather.py
+++ b/tests/test_inkycal_weather.py
@@ -34,7 +34,7 @@ tests = [
"padding_x": 10,
"padding_y": 10,
"fontsize": 12,
- "language": "en"
+ "language": "de"
}
},
{
diff --git a/tests/test_inkycal_webshot.py b/tests/test_inkycal_webshot.py
index b86c965..073a437 100755
--- a/tests/test_inkycal_webshot.py
+++ b/tests/test_inkycal_webshot.py
@@ -16,33 +16,13 @@ preview = Inkyimage.preview
merge = Inkyimage.merge
tests = [
- {
- "position": 1,
- "name": "Webshot",
- "config": {
- "size": [400, 100],
- "url": "https://github.com",
- "palette": "bwr",
- "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
- }
- },
{
"position": 1,
"name": "Webshot",
"config": {
"size": [400, 200],
- "url": "https://github.com",
- "palette": "bwy",
- "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
- }
- },
- {
- "position": 1,
- "name": "Webshot",
- "config": {
- "size": [400, 300],
- "url": "https://github.com",
- "palette": "bw",
+ "url": "https://aceinnolab.com",
+ "palette": "bwr",
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
}
},
@@ -51,8 +31,31 @@ tests = [
"name": "Webshot",
"config": {
"size": [400, 400],
- "url": "https://github.com",
+ "url": "https://aceinnolab.com",
+ "palette": "bwy",
+ "rotation": 0,
+ "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
+ }
+ },
+ {
+ "position": 1,
+ "name": "Webshot",
+ "config": {
+ "size": [400, 600],
+ "url": "https://aceinnolab.com",
+ "palette": "bw",
+ "rotation": 90,
+ "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
+ }
+ },
+ {
+ "position": 1,
+ "name": "Webshot",
+ "config": {
+ "size": [400, 800],
+ "url": "https://aceinnolab.com",
"palette": "bwr",
+ "rotation": 180,
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
}
}