Merge remote-tracking branch 'origin/main'

This commit is contained in:
Ace
2024-08-13 04:07:26 +02:00
67 changed files with 1769 additions and 541 deletions

View File

@@ -156,7 +156,7 @@ class Simple(inkycal_module):
# -----------------------------------------------------------------------#
# give an OK message
print(f'{__name__} loaded')
logger.debug(f'{__name__} loaded')
#############################################################################
# Validation of module specific parameters (optional) #

View File

@@ -27,7 +27,7 @@ class Inkyimage:
self.image = image
# give an OK message
logger.info(f"{__name__} loaded")
logger.debug(f"{__name__} loaded")
def load(self, path: str) -> None:
"""loads an image from a URL or filepath.
@@ -59,7 +59,7 @@ class Inkyimage:
logger.error("Invalid Image file provided", exc_info=True)
raise Exception("Please check if the path points to an image file.")
logger.info(f"width: {image.width}, height: {image.height}")
logger.debug(f"width: {image.width}, height: {image.height}")
image.convert(mode="RGBA") # convert to a more suitable format
self.image = image

View File

@@ -2,9 +2,7 @@
Inkycal Agenda Module
Copyright by aceinnolab
"""
import arrow
import arrow # noqa
from inkycal.custom import *
from inkycal.modules.ical_parser import iCalendar
from inkycal.modules.template import inkycal_module
@@ -77,8 +75,10 @@ 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
print(f'{__name__} loaded')
logger.debug(f'{__name__} loaded')
def generate_image(self):
"""Generate image for this module"""
@@ -88,7 +88,7 @@ class Agenda(inkycal_module):
im_height = int(self.height - (2 * self.padding_top))
im_size = im_width, im_height
logger.info(f'Image size: {im_size}')
logger.debug(f'Image size: {im_size}')
# Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size=im_size, color='white')
@@ -203,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),

View File

@@ -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']
@@ -84,7 +84,7 @@ class Calendar(inkycal_module):
)
# give an OK message
print(f'{__name__} loaded')
logger.debug(f'{__name__} loaded')
@staticmethod
def flatten(values):
@@ -100,7 +100,7 @@ class Calendar(inkycal_module):
im_size = im_width, im_height
events_height = 0
logger.info(f'Image size: {im_size}')
logger.debug(f'Image size: {im_size}')
# Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size=im_size, color='white')
@@ -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}")
@@ -265,7 +265,7 @@ class Calendar(inkycal_module):
# find out how many lines can fit at max in the event section
line_spacing = 2
text_bbox_height = self.font.getbbox("hg")
line_height = text_bbox_height[3] + line_spacing
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
@@ -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.4, 0.2),
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']

View File

@@ -60,7 +60,7 @@ class Feeds(inkycal_module):
self.shuffle_feeds = config["shuffle_feeds"]
# give an OK message
print(f'{__name__} loaded')
logger.debug(f'{__name__} loaded')
def _validate(self):
"""Validate module-specific parameters"""
@@ -75,7 +75,7 @@ class Feeds(inkycal_module):
im_width = int(self.width - (2 * self.padding_left))
im_height = int(self.height - (2 * self.padding_top))
im_size = im_width, im_height
logger.info(f'Image size: {im_size}')
logger.debug(f'Image size: {im_size}')
# Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size=im_size, color='white')
@@ -83,8 +83,9 @@ class Feeds(inkycal_module):
# Check if internet is available
if internet_available():
logger.info('Connection test passed')
logger.debug('Connection test passed')
else:
logger.error("Network not reachable. Please check your connection.")
raise NetworkNotReachableError
# Set some parameters for formatting feeds

View File

@@ -23,16 +23,18 @@ from icons.weather_icons.weather_icons import get_weather_icon
from inkycal.custom.functions import fonts
from inkycal.custom.functions import get_system_tz
from inkycal.custom.functions import internet_available
from inkycal.custom.functions import top_level
from inkycal.custom.inkycal_exceptions import NetworkNotReachableError
from inkycal.custom.openweathermap_wrapper import OpenWeatherMap
from inkycal.modules.inky_image import image_to_palette
from inkycal.modules.template import inkycal_module
from inkycal.settings import Settings
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
icons_dir = os.path.join(top_level, "icons", "ui-icons")
settings = Settings()
icons_dir = os.path.join(settings.FONT_PATH, "ui-icons")
def outline(image: Image, size: int, color: tuple) -> Image:
@@ -139,7 +141,7 @@ class Fullweather(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
@@ -237,7 +239,7 @@ class Fullweather(inkycal_module):
self.left_section_width = int(self.width / 4)
# give an OK message
print(f"{__name__} loaded")
logger.debug(f"{__name__} loaded")
def createBaseImage(self):
"""

View File

@@ -50,7 +50,7 @@ class Inkyimage(inkycal_module):
self.dither = False
# give an OK message
print(f"{__name__} loaded")
logger.debug(f"{__name__} loaded")
def generate_image(self):
"""Generate image for this module"""
@@ -71,7 +71,7 @@ class Inkyimage(inkycal_module):
# Remove background if present
im.remove_alpha()
# if autoflip was enabled, flip the image
# if auto-flip was enabled, flip the image
if self.autoflip:
im.autoflip(self.orientation)

View File

@@ -30,7 +30,7 @@ class Jokes(inkycal_module):
config = config['config']
# give an OK message
print(f'{__name__} loaded')
logger.debug(f'{__name__} loaded')
def generate_image(self):
"""Generate image for this module"""
@@ -39,7 +39,7 @@ class Jokes(inkycal_module):
im_width = int(self.width - (2 * self.padding_left))
im_height = int(self.height - (2 * self.padding_top))
im_size = im_width, im_height
logger.info(f'image size: {im_width} x {im_height} px')
logger.debug(f'image size: {im_width} x {im_height} px')
# Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size=im_size, color='white')
@@ -47,8 +47,9 @@ class Jokes(inkycal_module):
# Check if internet is available
if internet_available():
logger.info('Connection test passed')
logger.debug('Connection test passed')
else:
logger.error("Network not reachable. Please check your connection.")
raise NetworkNotReachableError
# Set some parameters for formatting feeds

View File

@@ -67,7 +67,7 @@ class Inkyserver(inkycal_module):
self.path_body = config['path_body']
# give an OK message
print(f'{__name__} loaded')
logger.debug(f'{__name__} loaded')
def generate_image(self):
"""Generate image for this module"""

View File

@@ -8,13 +8,13 @@ from inkycal.custom import *
# PIL has a class named Image, use alias for Inkyimage -> Images
from inkycal.modules.inky_image import Inkyimage as Images, image_to_palette
from inkycal.modules.template import inkycal_module
from inkycal.utils import JSONCache
logger = logging.getLogger(__name__)
class Slideshow(inkycal_module):
"""Cycles through images in a local image folder
"""
"""Cycles through images in a local image folder"""
name = "Slideshow - cycle through images from a local folder"
requires = {
@@ -53,7 +53,7 @@ class Slideshow(inkycal_module):
# required parameters
for param in self.requires:
if not param in config:
if param not in config:
raise Exception(f'config is missing {param}')
# optional parameters
@@ -64,19 +64,20 @@ class Slideshow(inkycal_module):
# Get the full path of all png/jpg/jpeg images in the given folder
all_files = glob.glob(f'{self.path}/*')
self.images = [i for i in all_files
if i.split('.')[-1].lower() in ('jpg', 'jpeg', 'png')]
self.images = [i for i in all_files if i.split('.')[-1].lower() in ('jpg', 'jpeg', 'png')]
if not self.images:
logger.error('No images found in the given folder, please '
'double check your path!')
logger.error('No images found in the given folder, please double check your path!')
raise Exception('No images found in the given folder path :/')
self.cache = JSONCache('inkycal_slideshow')
self.cache_data = self.cache.read()
# set a 'first run' signal
self._first_run = True
# give an OK message
print(f'{__name__} loaded')
logger.debug(f'{__name__} loaded')
def generate_image(self):
"""Generate image for this module"""
@@ -86,17 +87,19 @@ class Slideshow(inkycal_module):
im_height = int(self.height - (2 * self.padding_top))
im_size = im_width, im_height
logger.info(f'Image size: {im_size}')
logger.debug(f'Image size: {im_size}')
# rotates list items by 1 index
def rotate(somelist):
return somelist[1:] + somelist[:1]
def rotate(list: list):
return list[1:] + list[:1]
# Switch to the next image if this is not the first run
if self._first_run:
self._first_run = False
self.cache_data["current_index"] = 0
else:
self.images = rotate(self.images)
self.cache_data["current_index"] = (self.cache_data["current_index"] + 1) % len(self.images)
# initialize custom image class
im = Images()
@@ -110,7 +113,7 @@ class Slideshow(inkycal_module):
# Remove background if present
im.remove_alpha()
# if autoflip was enabled, flip the image
# if auto-flip was enabled, flip the image
if self.autoflip:
im.autoflip(self.orientation)
@@ -123,6 +126,8 @@ class Slideshow(inkycal_module):
# with the images now send, clear the current image
im.clear()
self.cache.write(self.cache_data)
# return images
return im_black, im_colour

View File

@@ -54,7 +54,7 @@ class Stocks(inkycal_module):
self.tickers = config['tickers']
# give an OK message
print(f'{__name__} loaded')
logger.debug(f'{__name__} loaded')
def generate_image(self):
"""Generate image for this module"""
@@ -63,7 +63,7 @@ class Stocks(inkycal_module):
im_width = int(self.width - (2 * self.padding_left))
im_height = int(self.height - (2 * self.padding_top))
im_size = im_width, im_height
logger.info(f'image size: {im_width} x {im_height} px')
logger.debug(f'image size: {im_width} x {im_height} px')
# Create an image for black pixels and one for coloured pixels (required)
im_black = Image.new('RGB', size=im_size, color='white')
@@ -142,7 +142,7 @@ class Stocks(inkycal_module):
logger.warning(f"Failed to get '{stockName}' ticker price hint! Using "
"default precision of 2 instead.")
stockHistory = yfTicker.history("30d")
stockHistory = yfTicker.history("1mo")
stockHistoryLen = len(stockHistory)
logger.info(f'fetched {stockHistoryLen} datapoints ...')
previousQuote = (stockHistory.tail(2)['Close'].iloc[0])

View File

@@ -31,7 +31,7 @@ class TextToDisplay(inkycal_module):
self.make_request = True if self.filepath.startswith("https://") else False
# give an OK message
print(f'{__name__} loaded')
logger.debug(f'{__name__} loaded')
def _validate(self):
"""Validate module-specific parameters"""
@@ -45,7 +45,7 @@ class TextToDisplay(inkycal_module):
im_width = int(self.width - (2 * self.padding_left))
im_height = int(self.height - (2 * self.padding_top))
im_size = im_width, im_height
logger.info(f'Image size: {im_size}')
logger.debug(f'Image size: {im_size}')
# Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size=im_size, color='white')

View File

@@ -32,7 +32,7 @@ class Tindie(inkycal_module):
# self.mode = config['mode'] # unshipped_orders, shipped_orders, all_orders
# give an OK message
print(f'{__name__} loaded')
logger.debug(f'{__name__} loaded')
def generate_image(self):
"""Generate image for this module"""
@@ -40,7 +40,7 @@ class Tindie(inkycal_module):
im_width = int(self.width - (2 * self.padding_left))
im_height = int(self.height - (2 * self.padding_top))
im_size = im_width, im_height
logger.info(f'image size: {im_width} x {im_height} px')
logger.debug(f'image size: {im_width} x {im_height} px')
# Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size=im_size, color='white')
@@ -50,6 +50,7 @@ class Tindie(inkycal_module):
if internet_available():
logger.info('Connection test passed')
else:
logger.error("Network not reachable. Please check your connection.")
raise NetworkNotReachableError
# Set some parameters for formatting feeds

View File

@@ -56,7 +56,7 @@ class Todoist(inkycal_module):
self._api = TodoistAPI(config['api_key'])
# give an OK message
print(f'{__name__} loaded')
logger.debug(f'{__name__} loaded')
def _validate(self):
"""Validate module-specific parameters"""
@@ -70,7 +70,7 @@ class Todoist(inkycal_module):
im_width = int(self.width - (2 * self.padding_left))
im_height = int(self.height - (2 * self.padding_top))
im_size = im_width, im_height
logger.info(f'Image size: {im_size}')
logger.debug(f'Image size: {im_size}')
# Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size=im_size, color='white')
@@ -80,6 +80,7 @@ class Todoist(inkycal_module):
if internet_available():
logger.info('Connection test passed')
else:
logger.error("Network not reachable. Please check your connection.")
raise NetworkNotReachableError
# Set some parameters for formatting todos

View File

@@ -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":
@@ -143,9 +143,7 @@ class Weather(inkycal_module):
self.tempDispUnit = "°"
# give an OK message
print(f"{__name__} loaded")
logger.debug(f"{__name__} loaded")
def generate_image(self):
"""Generate image for this module"""
@@ -154,7 +152,7 @@ class Weather(inkycal_module):
im_width = int(self.width - (2 * self.padding_left))
im_height = int(self.height - (2 * self.padding_top))
im_size = im_width, im_height
logger.info(f'Image size: {im_size}')
logger.debug(f'Image size: {im_size}')
# Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size=im_size, color='white')
@@ -162,8 +160,9 @@ class Weather(inkycal_module):
# Check if internet is available
if internet_available():
logger.info('Connection test passed')
logger.debug('Connection test passed')
else:
logger.error("Network not reachable. Please check your connection.")
raise NetworkNotReachableError
def get_moon_phase():
@@ -190,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
@@ -223,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 = {
@@ -263,7 +269,6 @@ class Weather(inkycal_module):
'\uf0a0': 0,
'\uf0a3': 0,
'\uf0a7': 0,
'\uf0aa': 0,
'\uf0ae': 0
}
@@ -277,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:]
@@ -289,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)
@@ -349,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)
@@ -378,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')
@@ -404,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}')
@@ -424,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':
@@ -433,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")
@@ -513,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=self.locale)
icon = weather_icons[fc_data[f'fc{pos}']['icon']]
temp = fc_data[f'fc{pos}']['temp']

View File

@@ -40,7 +40,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):
@@ -72,8 +75,14 @@ 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
print(f'Inkycal webshot loaded')
logger.debug(f'Inkycal webshot loaded')
def generate_image(self):
"""Generate image for this module"""
@@ -89,7 +98,7 @@ class Webshot(inkycal_module):
im_width = int(self.width - (2 * self.padding_left))
im_height = int(self.height - (2 * self.padding_top))
im_size = im_width, im_height
logger.info('image size: {} x {} px'.format(im_width, im_height))
logger.debug('image size: {} x {} px'.format(im_width, im_height))
# Create an image for black pixels and one for coloured pixels (required)
im_black = Image.new('RGB', size=im_size, color='white')
@@ -99,12 +108,13 @@ class Webshot(inkycal_module):
if internet_available():
logger.info('Connection test passed')
else:
logger.error("Network not reachable. Please check your connection.")
raise Exception('Network could not be reached :/')
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,
@@ -150,11 +160,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')

View File

@@ -11,6 +11,8 @@ from inkycal.modules.template import inkycal_module
logger = logging.getLogger(__name__)
settings = Settings()
class Xkcd(inkycal_module):
name = "xkcd - Displays comics from xkcd.com by Randall Munroe"
@@ -51,13 +53,13 @@ class Xkcd(inkycal_module):
self.scale_filter = config['filter']
# give an OK message
print(f'Inkycal XKCD loaded')
logger.debug(f'Inkycal XKCD loaded')
def generate_image(self):
"""Generate image for this module"""
# Create tmp path
tmpPath = f"{top_level}/temp"
tmpPath = settings.TEMPORARY_FOLDER
if not os.path.exists(tmpPath):
os.mkdir(tmpPath)
@@ -66,7 +68,7 @@ class Xkcd(inkycal_module):
im_width = int(self.width - (2 * self.padding_left))
im_height = int(self.height - (2 * self.padding_top))
im_size = im_width, im_height
logger.info('image size: {} x {} px'.format(im_width, im_height))
logger.debug('image size: {} x {} px'.format(im_width, im_height))
# Create an image for black pixels and one for coloured pixels (required)
im_black = Image.new('RGB', size=im_size, color='white')
@@ -76,6 +78,7 @@ class Xkcd(inkycal_module):
if internet_available():
logger.info('Connection test passed')
else:
logger.error("Network not reachable. Please check your connection.")
raise Exception('Network could not be reached :/')
# Set some parameters for formatting feeds